From cd2ae030366ff4d4652a91b4c090ab128b8c82a9 Mon Sep 17 00:00:00 2001 From: fxzer Date: Mon, 6 Nov 2023 15:54:53 +0000 Subject: [PATCH] [release] Publish on GitHub Pages --- .DS_Store | Bin 0 -> 6148 bytes 404.html | 27 + .../MongoDB\347\254\224\350\256\260.html" | 485 +++++ ...\344\273\266\344\270\212\344\274\240.html" | 277 +++ ...\344\271\240\347\254\224\350\256\260.html" | 1003 ++++++++++ ...\344\274\240\346\226\207\344\273\266.html" | 175 ++ ...\344\271\240\347\254\224\350\256\260.html" | 251 +++ ...\344\271\240\347\254\224\350\256\260.html" | 41 + ...\346\200\273\347\273\223\344\270\200.html" | 381 ++++ ...\346\200\273\347\273\223\344\270\211.html" | 891 +++++++++ ...\346\200\273\347\273\223\344\272\214.html" | 783 ++++++++ ...\346\200\273\347\273\223\344\270\200.html" | 466 +++++ ...\347\220\206\345\255\246\344\271\240.html" | 31 + ...\346\274\217\347\254\224\350\256\260.html" | 127 ++ ...\346\230\276\344\274\230\345\214\226.html" | 367 ++++ ...\351\231\244\345\244\204\347\220\206.html" | 109 ++ ...\344\271\240\347\254\224\350\256\260.html" | 265 +++ ...\344\273\243\347\240\201\346\256\265.html" | 205 ++ ...\344\271\246\346\221\230\350\246\201.html" | 371 ++++ ...\347\224\250\346\223\215\344\275\234.html" | 145 ++ ...\347\253\257\347\276\216\345\214\226.html" | 59 + ...4\270\252\345\271\263\345\217\260SSH.html" | 67 + .../JavaScript/async\344\270\216await.html" | 227 +++ ...\346\224\257\344\274\230\345\214\226.html" | 147 ++ ...\346\207\222\345\212\240\350\275\275.html" | 81 + ...\345\244\215\344\271\240\344\270\200.html" | 143 ++ ...\345\244\215\344\271\240\344\272\214.html" | 445 +++++ ...\350\247\201\347\256\227\346\263\225.html" | 1713 +++++++++++++++++ .../\346\211\213\345\206\231Promise.html" | 1179 ++++++++++++ ...\346\215\256\345\216\273\351\207\215.html" | 559 ++++++ ...\346\261\202\351\233\206\345\220\210.html" | 189 ++ ...\344\273\266\347\263\273\347\273\237.html" | 201 ++ ...\350\241\250\350\276\276\345\274\217.html" | 267 +++ ...\345\275\225\347\273\223\346\236\204.html" | 119 ++ ...\351\230\266\345\207\275\346\225\260.html" | 323 ++++ ...\347\275\262\350\204\232\346\234\254.html" | 177 ++ ...\345\255\246\347\254\224\350\256\260.html" | 1017 ++++++++++ ...\347\224\250\346\212\200\345\267\247.html" | 83 + ...\344\273\266\350\257\246\350\247\243.html" | 295 +++ GoodTool/index.html | 31 + ...\347\216\257\346\234\272\345\210\266.html" | 31 + ...\346\261\202\350\277\207\347\250\213.html" | 31 + ...\346\234\272\347\275\221\347\273\234.html" | 31 + ...\351\235\242\350\257\225\351\242\230.html" | 185 ++ ...\351\235\242\350\257\225\351\242\230.html" | 171 ++ ...\351\235\242\350\257\225\351\242\230.html" | 31 + .../Promise\347\233\270\345\205\263.html" | 305 +++ ...\345\216\237\345\236\213\351\223\276.html" | 121 ++ ...\351\235\242\350\257\225\351\242\230.html" | 407 ++++ ...\347\224\250\346\226\271\346\263\225.html" | 63 + ...\351\235\242\350\257\225\351\242\230.html" | 429 +++++ ...\351\235\242\350\257\225\351\242\230.html" | 129 ++ ...\345\274\217\345\216\237\347\220\206.html" | 31 + ...\345\237\272\347\241\200\347\257\207.html" | 31 + ...\346\230\216\345\221\250\346\234\237.html" | 89 + ...\350\277\233\351\230\266\347\257\207.html" | 31 + ...\350\241\214\350\277\207\347\250\213.html" | 31 + ...\347\233\256\344\274\230\345\214\226.html" | 117 ++ ...\247\201Path\345\214\272\345\210\253.html" | 65 + ...\344\271\211\346\214\207\344\273\244.html" | 127 ++ Interview/index.html | 31 + ...\346\256\265\351\233\206\351\224\246.html" | 1211 ++++++++++++ ...\347\224\250\346\200\273\347\273\223.html" | 55 + ...\351\242\230\346\200\273\347\273\223.html" | 249 +++ ...\347\233\256\350\270\251\345\235\221.html" | 103 + ...\345\235\221\350\256\260\345\275\225.html" | 337 ++++ ...\345\235\221\350\256\260\345\275\225.html" | 35 + ...\350\270\251\345\235\221\344\270\200.html" | 435 +++++ Problem/index.html | 31 + ...DB\347\254\224\350\256\260.md.eb6021c2.js" | 455 +++++ ...7\254\224\350\256\260.md.eb6021c2.lean.js" | 1 + ...66\344\270\212\344\274\240.md.84c9f765.js" | 247 +++ ...4\270\212\344\274\240.md.84c9f765.lean.js" | 1 + ...40\347\254\224\350\256\260.md.f1b234ff.js" | 973 ++++++++++ ...7\254\224\350\256\260.md.f1b234ff.lean.js" | 1 + ...40\346\226\207\344\273\266.md.faa27b4e.js" | 145 ++ ...6\226\207\344\273\266.md.faa27b4e.lean.js" | 1 + ...40\347\254\224\350\256\260.md.d29feca6.js" | 221 +++ ...7\254\224\350\256\260.md.d29feca6.lean.js" | 1 + ...40\347\254\224\350\256\260.md.9d658cc4.js" | 11 + ...7\254\224\350\256\260.md.9d658cc4.lean.js" | 1 + ...73\347\273\223\344\270\200.md.25af9886.js" | 351 ++++ ...7\273\223\344\270\200.md.25af9886.lean.js" | 1 + ...73\347\273\223\344\270\211.md.574a1956.js" | 861 +++++++++ ...7\273\223\344\270\211.md.574a1956.lean.js" | 1 + ...73\347\273\223\344\272\214.md.0a8462a7.js" | 753 ++++++++ ...7\273\223\344\272\214.md.0a8462a7.lean.js" | 1 + ...73\347\273\223\344\270\200.md.fc5d41af.js" | 436 +++++ ...7\273\223\344\270\200.md.fc5d41af.lean.js" | 1 + ...06\345\255\246\344\271\240.md.8895a11d.js" | 1 + ...5\255\246\344\271\240.md.8895a11d.lean.js" | 1 + ...17\347\254\224\350\256\260.md.6422a5f9.js" | 97 + ...7\254\224\350\256\260.md.6422a5f9.lean.js" | 1 + ...76\344\274\230\345\214\226.md.8805bdc2.js" | 337 ++++ ...4\274\230\345\214\226.md.8805bdc2.lean.js" | 1 + ...44\345\244\204\347\220\206.md.9f59b85b.js" | 79 + ...5\244\204\347\220\206.md.9f59b85b.lean.js" | 1 + ...40\347\254\224\350\256\260.md.6624dd93.js" | 235 +++ ...7\254\224\350\256\260.md.6624dd93.lean.js" | 1 + ...43\347\240\201\346\256\265.md.083fb786.js" | 175 ++ ...7\240\201\346\256\265.md.083fb786.lean.js" | 1 + ...46\346\221\230\350\246\201.md.3689a434.js" | 341 ++++ ...6\221\230\350\246\201.md.3689a434.lean.js" | 1 + ...50\346\223\215\344\275\234.md.a0e87468.js" | 115 ++ ...6\223\215\344\275\234.md.a0e87468.lean.js" | 1 + ...57\347\276\216\345\214\226.md.6674896b.js" | 29 + ...7\276\216\345\214\226.md.6674896b.lean.js" | 1 + ...345\271\263\345\217\260SSH.md.49289c60.js" | 37 + ...71\263\345\217\260SSH.md.49289c60.lean.js" | 1 + ...ipt_async\344\270\216await.md.d21c9cb0.js" | 197 ++ ...sync\344\270\216await.md.d21c9cb0.lean.js" | 1 + ...57\344\274\230\345\214\226.md.e8fda00c.js" | 117 ++ ...4\274\230\345\214\226.md.e8fda00c.lean.js" | 1 + ...22\345\212\240\350\275\275.md.3d5465d0.js" | 51 + ...5\212\240\350\275\275.md.3d5465d0.lean.js" | 1 + ...15\344\271\240\344\270\200.md.a8906ce7.js" | 113 ++ ...4\271\240\344\270\200.md.a8906ce7.lean.js" | 1 + ...15\344\271\240\344\272\214.md.8f89af07.js" | 415 ++++ ...4\271\240\344\272\214.md.8f89af07.lean.js" | 1 + ...01\347\256\227\346\263\225.md.0cd56de3.js" | 1683 ++++++++++++++++ ...7\256\227\346\263\225.md.0cd56de3.lean.js" | 1 + ...211\213\345\206\231Promise.md.fbddbbf5.js" | 1149 +++++++++++ ...13\345\206\231Promise.md.fbddbbf5.lean.js" | 1 + ...56\345\216\273\351\207\215.md.f1eaba48.js" | 529 +++++ ...5\216\273\351\207\215.md.f1eaba48.lean.js" | 1 + ...02\351\233\206\345\220\210.md.9e71e873.js" | 159 ++ ...1\233\206\345\220\210.md.9e71e873.lean.js" | 1 + ...66\347\263\273\347\273\237.md.1488f287.js" | 171 ++ ...7\263\273\347\273\237.md.1488f287.lean.js" | 1 + ...50\350\276\276\345\274\217.md.a9560fb8.js" | 237 +++ ...0\276\276\345\274\217.md.a9560fb8.lean.js" | 1 + ...25\347\273\223\346\236\204.md.f15b6a8f.js" | 89 + ...7\273\223\346\236\204.md.f15b6a8f.lean.js" | 1 + ...66\345\207\275\346\225\260.md.f3e81d0b.js" | 293 +++ ...5\207\275\346\225\260.md.f3e81d0b.lean.js" | 1 + ...62\350\204\232\346\234\254.md.7ce896dd.js" | 147 ++ ...0\204\232\346\234\254.md.7ce896dd.lean.js" | 1 + ...46\347\254\224\350\256\260.md.a7be054a.js" | 987 ++++++++++ ...7\254\224\350\256\260.md.a7be054a.lean.js" | 1 + ...50\346\212\200\345\267\247.md.21fda5ca.js" | 53 + ...6\212\200\345\267\247.md.21fda5ca.lean.js" | 1 + ...66\350\257\246\350\247\243.md.7a55465d.js" | 265 +++ ...0\257\246\350\247\243.md.7a55465d.lean.js" | 1 + assets/GoodTool_index.md.2cde5d0e.js | 1 + assets/GoodTool_index.md.2cde5d0e.lean.js | 1 + ...57\346\234\272\345\210\266.md.9f053692.js" | 1 + ...6\234\272\345\210\266.md.9f053692.lean.js" | 1 + ...02\350\277\207\347\250\213.md.1acb73dd.js" | 1 + ...0\277\207\347\250\213.md.1acb73dd.lean.js" | 1 + ...72\347\275\221\347\273\234.md.73c84072.js" | 1 + ...7\275\221\347\273\234.md.73c84072.lean.js" | 1 + ...42\350\257\225\351\242\230.md.b72bdb12.js" | 155 ++ ...0\257\225\351\242\230.md.b72bdb12.lean.js" | 1 + ...42\350\257\225\351\242\230.md.6b9b42f1.js" | 141 ++ ...0\257\225\351\242\230.md.6b9b42f1.lean.js" | 1 + ...42\350\257\225\351\242\230.md.63a54546.js" | 1 + ...0\257\225\351\242\230.md.63a54546.lean.js" | 1 + ...se\347\233\270\345\205\263.md.1015a7af.js" | 275 +++ ...7\233\270\345\205\263.md.1015a7af.lean.js" | 1 + ...37\345\236\213\351\223\276.md.4ad216b5.js" | 91 + ...5\236\213\351\223\276.md.4ad216b5.lean.js" | 1 + ...42\350\257\225\351\242\230.md.0df982a7.js" | 377 ++++ ...0\257\225\351\242\230.md.0df982a7.lean.js" | 1 + ...50\346\226\271\346\263\225.md.4808f793.js" | 33 + ...6\226\271\346\263\225.md.4808f793.lean.js" | 1 + ...42\350\257\225\351\242\230.md.c89e986d.js" | 399 ++++ ...0\257\225\351\242\230.md.c89e986d.lean.js" | 1 + ...42\350\257\225\351\242\230.md.0abc2056.js" | 99 + ...0\257\225\351\242\230.md.0abc2056.lean.js" | 1 + ...17\345\216\237\347\220\206.md.2eeac150.js" | 1 + ...5\216\237\347\220\206.md.2eeac150.lean.js" | 1 + ...72\347\241\200\347\257\207.md.d7fd744f.js" | 1 + ...7\241\200\347\257\207.md.d7fd744f.lean.js" | 1 + ...16\345\221\250\346\234\237.md.4220f397.js" | 59 + ...5\221\250\346\234\237.md.4220f397.lean.js" | 1 + ...33\351\230\266\347\257\207.md.786b9622.js" | 1 + ...1\230\266\347\257\207.md.786b9622.lean.js" | 1 + ...14\350\277\207\347\250\213.md.9da37746.js" | 1 + ...0\277\207\347\250\213.md.9da37746.lean.js" | 1 + ...56\344\274\230\345\214\226.md.3cd67a0e.js" | 87 + ...4\274\230\345\214\226.md.3cd67a0e.lean.js" | 1 + ...th\345\214\272\345\210\253.md.56f4fc59.js" | 35 + ...5\214\272\345\210\253.md.56f4fc59.lean.js" | 1 + ...11\346\214\207\344\273\244.md.3d2ea0a9.js" | 97 + ...6\214\207\344\273\244.md.3d2ea0a9.lean.js" | 1 + assets/Interview_index.md.ff0a75dc.js | 1 + assets/Interview_index.md.ff0a75dc.lean.js | 1 + ...65\351\233\206\351\224\246.md.3d28f150.js" | 1181 ++++++++++++ ...1\233\206\351\224\246.md.3d28f150.lean.js" | 1 + ...50\346\200\273\347\273\223.md.10b596c9.js" | 25 + ...6\200\273\347\273\223.md.10b596c9.lean.js" | 1 + ...30\346\200\273\347\273\223.md.fe67d408.js" | 219 +++ ...6\200\273\347\273\223.md.fe67d408.lean.js" | 1 + ...56\350\270\251\345\235\221.md.e3bdda07.js" | 73 + ...0\270\251\345\235\221.md.e3bdda07.lean.js" | 1 + ...21\350\256\260\345\275\225.md.007e02bc.js" | 307 +++ ...0\256\260\345\275\225.md.007e02bc.lean.js" | 1 + ...21\350\256\260\345\275\225.md.d7553dcf.js" | 5 + ...0\256\260\345\275\225.md.d7553dcf.lean.js" | 1 + ...51\345\235\221\344\270\200.md.5d32b46a.js" | 405 ++++ ...5\235\221\344\270\200.md.5d32b46a.lean.js" | 1 + assets/Problem_index.md.724652c6.js | 1 + assets/Problem_index.md.724652c6.lean.js | 1 + assets/app.c5d8d5ce.js | 1 + .../chunks/@localSearchIndexroot.20abec5d.js | 1 + assets/chunks/DemoWrap.1b6e7adf.js | 1 + assets/chunks/VPLocalSearchBox.0bede1e4.js | 7 + assets/chunks/framework.c53372a0.js | 2 + assets/chunks/theme.1e9d2528.js | 1 + assets/index.md.4cc1630f.js | 1 + assets/index.md.4cc1630f.lean.js | 1 + .../inter-italic-cyrillic-ext.33bd5a8e.woff2 | Bin 0 -> 28332 bytes assets/inter-italic-cyrillic.ea42a392.woff2 | Bin 0 -> 17824 bytes assets/inter-italic-greek-ext.4fbe9427.woff2 | Bin 0 -> 12188 bytes assets/inter-italic-greek.8f4463c4.woff2 | Bin 0 -> 23264 bytes assets/inter-italic-latin-ext.bd8920cc.woff2 | Bin 0 -> 63552 bytes assets/inter-italic-latin.bd3b6f56.woff2 | Bin 0 -> 46048 bytes assets/inter-italic-vietnamese.6ce511fb.woff2 | Bin 0 -> 8784 bytes .../inter-roman-cyrillic-ext.e75737ce.woff2 | Bin 0 -> 26600 bytes assets/inter-roman-cyrillic.5f2c6c8c.woff2 | Bin 0 -> 16780 bytes assets/inter-roman-greek-ext.ab0619bc.woff2 | Bin 0 -> 11808 bytes assets/inter-roman-greek.d5a6d92a.woff2 | Bin 0 -> 21776 bytes assets/inter-roman-latin-ext.0030eebd.woff2 | Bin 0 -> 59608 bytes assets/inter-roman-latin.2ed14f66.woff2 | Bin 0 -> 42464 bytes assets/inter-roman-vietnamese.14ce25a6.woff2 | Bin 0 -> 8492 bytes assets/style.ca30dd5f.css | 1 + favicon.ico | Bin 0 -> 4286 bytes hashmap.json | 1 + index.html | 31 + logo.svg | 21 + manifest.webmanifest | 1 + pwa-192x192.png | Bin 0 -> 35142 bytes pwa-512x512.png | Bin 0 -> 220652 bytes registerSW.js | 1 + sitemap.xml | 1 + socialIcons.ts | 9 + sw.js | 1 + workbox-fa446783.js | 1 + 238 files changed, 35443 insertions(+) create mode 100644 .DS_Store create mode 100644 404.html create mode 100644 "BackEnd/NodeJS/MongoDB\347\254\224\350\256\260.html" create mode 100644 "BackEnd/NodeJS/Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.html" create mode 100644 "BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.html" create mode 100644 "BackEnd/NodeJS/Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.html" create mode 100644 "BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.html" create mode 100644 "BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.html" create mode 100644 "Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" create mode 100644 "Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.html" create mode 100644 "Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.html" create mode 100644 "Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" create mode 100644 "Framework/Vue/Vite\345\216\237\347\220\206\345\255\246\344\271\240.html" create mode 100644 "Framework/Vue/Vue3\350\241\245\346\274\217\347\254\224\350\256\260.html" create mode 100644 "Framework/Vue/\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.html" create mode 100644 "Framework/Vue/\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.html" create mode 100644 "FrontEnd/CSS/Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.html" create mode 100644 "FrontEnd/CSS/\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.html" create mode 100644 "FrontEnd/CSS/\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.html" create mode 100644 "FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.html" create mode 100644 "FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.html" create mode 100644 "FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.html" create mode 100644 "FrontEnd/JavaScript/async\344\270\216await.html" create mode 100644 "FrontEnd/JavaScript/\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.html" create mode 100644 "FrontEnd/JavaScript/\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.html" create mode 100644 "FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.html" create mode 100644 "FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.html" create mode 100644 "FrontEnd/JavaScript/\345\270\270\350\247\201\347\256\227\346\263\225.html" create mode 100644 "FrontEnd/JavaScript/\346\211\213\345\206\231Promise.html" create mode 100644 "FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.html" create mode 100644 "FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.html" create mode 100644 "FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.html" create mode 100644 "FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" create mode 100644 "FrontEnd/JavaScript/\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.html" create mode 100644 "FrontEnd/JavaScript/\351\253\230\351\230\266\345\207\275\346\225\260.html" create mode 100644 "FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.html" create mode 100644 "FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.html" create mode 100644 "FrontEnd/TypeScript/\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.html" create mode 100644 "FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.html" create mode 100644 GoodTool/index.html create mode 100644 "Interview/Brower/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" create mode 100644 "Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.html" create mode 100644 "Interview/Brower/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.html" create mode 100644 "Interview/CSS/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" create mode 100644 "Interview/CSS/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" create mode 100644 "Interview/CSS/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" create mode 100644 "Interview/JavaScript/Promise\347\233\270\345\205\263.html" create mode 100644 "Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.html" create mode 100644 "Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" create mode 100644 "Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.html" create mode 100644 "Interview/JavaScript/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" create mode 100644 "Interview/JavaScript/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" create mode 100644 "Interview/Vue/Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.html" create mode 100644 "Interview/Vue/Vue\345\237\272\347\241\200\347\257\207.html" create mode 100644 "Interview/Vue/Vue\345\243\260\346\230\216\345\221\250\346\234\237.html" create mode 100644 "Interview/Vue/Vue\350\277\233\351\230\266\347\257\207.html" create mode 100644 "Interview/Vue/npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.html" create mode 100644 "Interview/Vue/\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.html" create mode 100644 "Interview/Vue/\345\270\270\350\247\201Path\345\214\272\345\210\253.html" create mode 100644 "Interview/Vue/\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.html" create mode 100644 Interview/index.html create mode 100644 "Problem/Graphical/Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.html" create mode 100644 "Problem/Graphical/Antv\344\275\277\347\224\250\346\200\273\347\273\223.html" create mode 100644 "Problem/Graphical/Echarts\351\227\256\351\242\230\346\200\273\347\273\223.html" create mode 100644 "Problem/Nuxt3/Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.html" create mode 100644 "Problem/VitePress/VitePress\350\270\251\345\235\221\350\256\260\345\275\225.html" create mode 100644 "Problem/VitePress/VuePress\350\270\251\345\235\221\350\256\260\345\275\225.html" create mode 100644 "Problem/VueProject/Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.html" create mode 100644 Problem/index.html create mode 100644 "assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.js" create mode 100644 "assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.lean.js" create mode 100644 "assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.js" create mode 100644 "assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.lean.js" create mode 100644 "assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.js" create mode 100644 "assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.lean.js" create mode 100644 "assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.js" create mode 100644 "assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.lean.js" create mode 100644 "assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.js" create mode 100644 "assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.lean.js" create mode 100644 "assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.js" create mode 100644 "assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.lean.js" create mode 100644 "assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.js" create mode 100644 "assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.lean.js" create mode 100644 "assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.js" create mode 100644 "assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.lean.js" create mode 100644 "assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.js" create mode 100644 "assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.lean.js" create mode 100644 "assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.js" create mode 100644 "assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.lean.js" create mode 100644 "assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.js" create mode 100644 "assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.lean.js" create mode 100644 "assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.js" create mode 100644 "assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.lean.js" create mode 100644 "assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.js" create mode 100644 "assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.lean.js" create mode 100644 "assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.js" create mode 100644 "assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.lean.js" create mode 100644 "assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.js" create mode 100644 "assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.lean.js" create mode 100644 "assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.js" create mode 100644 "assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.lean.js" create mode 100644 "assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.js" create mode 100644 "assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.lean.js" create mode 100644 "assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.js" create mode 100644 "assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.lean.js" create mode 100644 "assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.js" create mode 100644 "assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.lean.js" create mode 100644 "assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.js" create mode 100644 "assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.js" create mode 100644 "assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.js" create mode 100644 "assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.js" create mode 100644 "assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.js" create mode 100644 "assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.js" create mode 100644 "assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.lean.js" create mode 100644 "assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.js" create mode 100644 "assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.lean.js" create mode 100644 "assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.js" create mode 100644 "assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.lean.js" create mode 100644 "assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.js" create mode 100644 "assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.lean.js" create mode 100644 "assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.js" create mode 100644 "assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.lean.js" create mode 100644 "assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.js" create mode 100644 "assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.lean.js" create mode 100644 assets/GoodTool_index.md.2cde5d0e.js create mode 100644 assets/GoodTool_index.md.2cde5d0e.lean.js create mode 100644 "assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.js" create mode 100644 "assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.lean.js" create mode 100644 "assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.js" create mode 100644 "assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.lean.js" create mode 100644 "assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.js" create mode 100644 "assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.lean.js" create mode 100644 "assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.js" create mode 100644 "assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.lean.js" create mode 100644 "assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.js" create mode 100644 "assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.lean.js" create mode 100644 "assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.js" create mode 100644 "assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.lean.js" create mode 100644 "assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.js" create mode 100644 "assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.lean.js" create mode 100644 "assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.js" create mode 100644 "assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.lean.js" create mode 100644 "assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.js" create mode 100644 "assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.lean.js" create mode 100644 "assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.js" create mode 100644 "assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.lean.js" create mode 100644 "assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.js" create mode 100644 "assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.lean.js" create mode 100644 "assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.js" create mode 100644 "assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.lean.js" create mode 100644 "assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.js" create mode 100644 "assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.lean.js" create mode 100644 "assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.js" create mode 100644 "assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.lean.js" create mode 100644 "assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.js" create mode 100644 "assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.lean.js" create mode 100644 "assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.js" create mode 100644 "assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.lean.js" create mode 100644 "assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.js" create mode 100644 "assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.lean.js" create mode 100644 "assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.js" create mode 100644 "assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.lean.js" create mode 100644 "assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.js" create mode 100644 "assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.lean.js" create mode 100644 "assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.js" create mode 100644 "assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.lean.js" create mode 100644 assets/Interview_index.md.ff0a75dc.js create mode 100644 assets/Interview_index.md.ff0a75dc.lean.js create mode 100644 "assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.js" create mode 100644 "assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.lean.js" create mode 100644 "assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.js" create mode 100644 "assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.lean.js" create mode 100644 "assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.js" create mode 100644 "assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.lean.js" create mode 100644 "assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.js" create mode 100644 "assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.lean.js" create mode 100644 "assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.js" create mode 100644 "assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.lean.js" create mode 100644 "assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.js" create mode 100644 "assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.lean.js" create mode 100644 "assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.js" create mode 100644 "assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.lean.js" create mode 100644 assets/Problem_index.md.724652c6.js create mode 100644 assets/Problem_index.md.724652c6.lean.js create mode 100644 assets/app.c5d8d5ce.js create mode 100644 assets/chunks/@localSearchIndexroot.20abec5d.js create mode 100644 assets/chunks/DemoWrap.1b6e7adf.js create mode 100644 assets/chunks/VPLocalSearchBox.0bede1e4.js create mode 100644 assets/chunks/framework.c53372a0.js create mode 100644 assets/chunks/theme.1e9d2528.js create mode 100644 assets/index.md.4cc1630f.js create mode 100644 assets/index.md.4cc1630f.lean.js create mode 100644 assets/inter-italic-cyrillic-ext.33bd5a8e.woff2 create mode 100644 assets/inter-italic-cyrillic.ea42a392.woff2 create mode 100644 assets/inter-italic-greek-ext.4fbe9427.woff2 create mode 100644 assets/inter-italic-greek.8f4463c4.woff2 create mode 100644 assets/inter-italic-latin-ext.bd8920cc.woff2 create mode 100644 assets/inter-italic-latin.bd3b6f56.woff2 create mode 100644 assets/inter-italic-vietnamese.6ce511fb.woff2 create mode 100644 assets/inter-roman-cyrillic-ext.e75737ce.woff2 create mode 100644 assets/inter-roman-cyrillic.5f2c6c8c.woff2 create mode 100644 assets/inter-roman-greek-ext.ab0619bc.woff2 create mode 100644 assets/inter-roman-greek.d5a6d92a.woff2 create mode 100644 assets/inter-roman-latin-ext.0030eebd.woff2 create mode 100644 assets/inter-roman-latin.2ed14f66.woff2 create mode 100644 assets/inter-roman-vietnamese.14ce25a6.woff2 create mode 100644 assets/style.ca30dd5f.css create mode 100644 favicon.ico create mode 100644 hashmap.json create mode 100644 index.html create mode 100644 logo.svg create mode 100644 manifest.webmanifest create mode 100644 pwa-192x192.png create mode 100644 pwa-512x512.png create mode 100644 registerSW.js create mode 100644 sitemap.xml create mode 100644 socialIcons.ts create mode 100644 sw.js create mode 100644 workbox-fa446783.js diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b016fdeaa022a65ad32ad7e0a3134cdd8c0e50e6 GIT binary patch literal 6148 zcmeHK%SyvQ6g{I|1l)A#GGAcu4?>AM5vAzb)W%||ZAcqXSNU|$y?1FMp;{r9-Sk$}O^+2IxG|Ac%tgyj?{nz^2 z?XIEk4pY2iiybPwBEtitR%j_#v}Pz!(pOTtr(U5^>oYBDykSZEEp1Z0p-n27zGUnZ zGes*^df`}U#SJB?{h{^d%r^Z;s=0z0*C9FCA3L~-JJ{RZG5!p`CTGAIa0Z-#12Vun zTUv5v=%X{>3^)Vd49NMAvJ2)BJ3~D>IOr3AIHFk_WqC_TP8uqKCq-1`WiBIn4tI?bPo%(y&aXDC&~uIWVo N5KuyVa0U**z$Yr+JdFSV literal 0 HcmV?d00001 diff --git a/404.html b/404.html new file mode 100644 index 00000000..6cb760f8 --- /dev/null +++ b/404.html @@ -0,0 +1,27 @@ + + + + + + 404 | ZerDocs + + + + + + + + + + + + +
Skip to content

404

PAGE NOT FOUND

But if you don't change your direction, and if you keep looking, you may end up where you are heading.
+ + + + \ No newline at end of file diff --git "a/BackEnd/NodeJS/MongoDB\347\254\224\350\256\260.html" "b/BackEnd/NodeJS/MongoDB\347\254\224\350\256\260.html" new file mode 100644 index 00000000..65a30a19 --- /dev/null +++ "b/BackEnd/NodeJS/MongoDB\347\254\224\350\256\260.html" @@ -0,0 +1,485 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、相关概念

MongoDB是文档型的NoSQL数据库

image-20220508194905648

image-20220507220553150

优点

  1. 高性能

  2. 高可用性

  3. 可扩展分片集群

应用场景:(数据量大、读写操作频繁、对事务要求不高)

二、数据库操作

查看所有数据库

sh
show databases
+show dbs
+#连接数据库后默认在test库
+use testdb01 	#切换数据库
show databases
+show dbs
+#连接数据库后默认在test库
+use testdb01 	#切换数据库

image-20220507215028603

创建/删除数据库

shell
use 数据库名 	# use testdb01
+db 	#查看所在数据库
+db.dropDatabase() 	#删除当前所在库
use 数据库名 	# use testdb01
+db 	#查看所在数据库
+db.dropDatabase() 	#删除当前所在库

三、集合相关操作

shell
show collections; 	# 查看数据库集合	show tables;
+db.createCollection('collectionName',[option]);	 #显式创建集合
+db.users.insert({'name':'李四'}); 	#隐式创建集合 往不存在的集合插入数据
+db.users.drop(); 	#删除集合
show collections; 	# 查看数据库集合	show tables;
+db.createCollection('collectionName',[option]);	 #显式创建集合
+db.users.insert({'name':'李四'}); 	#隐式创建集合 往不存在的集合插入数据
+db.users.drop(); 	#删除集合

四、文档相关操作

1.查询

shell
db.users.find() 	#查询所有 SELECT * from users  
+db.getCollection('users').find()	#查询所有
+db.getCollection('users').findOne()	#查询第一个
+db.getCollection('users').findOne({name:'zhang3'})		#查询符合条件的第一个
+
+db.users.find( { name: 1, age: 1 } ) 	#SELECT _id,name,age from users 
+db.users.find( {  name: 1, age: 1, _id: 0 } ) 	#去除id字段
+db.users.find( { name: 0, age: 0 } ) 	#去除特定字段
+db.users.find().pretty() 	#格式化查询(适用于长/复杂数据)
db.users.find() 	#查询所有 SELECT * from users  
+db.getCollection('users').find()	#查询所有
+db.getCollection('users').findOne()	#查询第一个
+db.getCollection('users').findOne({name:'zhang3'})		#查询符合条件的第一个
+
+db.users.find( { name: 1, age: 1 } ) 	#SELECT _id,name,age from users 
+db.users.find( {  name: 1, age: 1, _id: 0 } ) 	#去除id字段
+db.users.find( { name: 0, age: 0 } ) 	#去除特定字段
+db.users.find().pretty() 	#格式化查询(适用于长/复杂数据)
  • 等值查询
shell
db.users.find( { age:18} )
+#	WHERE age = 18
db.users.find( { age:18} )
+#	WHERE age = 18
  • AND条件
shell
db.users.find( { age: { $lt: 30 } ,sex:'',} )
+#	WHERE sex = "男" AND age < 30
+db.users.find( { age:24, age: { $lt: 30 } } )  #相同字段and查询中出现多次,以最后一个为查询条件
+#	WHERE age < 30
db.users.find( { age: { $lt: 30 } ,sex:'',} )
+#	WHERE sex = "男" AND age < 30
+db.users.find( { age:24, age: { $lt: 30 } } )  #相同字段and查询中出现多次,以最后一个为查询条件
+#	WHERE age < 30
  • OR条件
shell
db.users.find( { $or: [{sex:'男'}, { age: { $lt: 30 } } ] } )
+#	WHERE sex = "男" OR age < 30
db.users.find( { $or: [{sex:'男'}, { age: { $lt: 30 } } ] } )
+#	WHERE sex = "男" OR age < 30
  • 同时使用AND和OR条件
shell
db.users.find( {
+    { like:'美女'},
+     $or: [{sex:'男'}, { age: { $lt: 30 } },{ name: /^p/ } ] 
+} )
+#	WHERE like = "美女" AND (sex = "男" OR age < 30 OR name LIKE "%p%")
db.users.find( {
+    { like:'美女'},
+     $or: [{sex:'男'}, { age: { $lt: 30 } },{ name: /^p/ } ] 
+} )
+#	WHERE like = "美女" AND (sex = "男" OR age < 30 OR name LIKE "%p%")
  • 查询条件中使用查询操作符
shell
db.users.find( { age: { $in: [ "20", "22" ] } } )
db.users.find( { age: { $in: [ "20", "22" ] } } )
  • 模糊查询
shell
db.users.find( { name:/张/} ) #查询名字中含有'张'的所有
+# WHERE name LIKE "%张%
db.users.find( { name:/张/} ) #查询名字中含有'张'的所有
+# WHERE name LIKE "%张%
  • 数组中的查询
shell
db.users.find(likes:{$size:3})	#查询'喜好'数组大小为3
db.users.find(likes:{$size:3})	#查询'喜好'数组大小为3
  • 排序
shell
db.users.find().sort({age:-1}) # 1 升序 	-1 降序 (没有这个字段的数据排在前面)
db.users.find().sort({age:-1}) # 1 升序 	-1 降序 (没有这个字段的数据排在前面)
  • 分页
shell
db.users.find().skip(40).limit(30) # 跳过40条数据查30条数据 (起始0,则从40开始)
db.users.find().skip(40).limit(30) # 跳过40条数据查30条数据 (起始0,则从40开始)
  • 条数
shell
db.users.find().count()
db.users.find().count()
  • 去重
shell
db.users.find().distinct('字段')
db.users.find().distinct('字段')
  • 对比语法:

image-20220507231641824

2.插入

  • 单条文档
shell
db.users.insert({'name':'李四',age:18,sex:''});  # 提示已弃用
+db.getCollection('users').insert({'name':'李四',age:18,sex:''})
+db.users.insertOne({'name':'赵六'})
db.users.insert({'name':'李四',age:18,sex:''});  # 提示已弃用
+db.getCollection('users').insert({'name':'李四',age:18,sex:''})
+db.users.insertOne({'name':'赵六'})
  • 多条文档
shell
db.users.insert([{name:'缘一'},{name:'二楞'}])
+db.users.insertMany([{name:'缘一1'},{name:'二楞1'}])
+db.getCollection('users').insertMany([{name:'zhang3',age:19},{name:'zhang4',age:19}])
db.users.insert([{name:'缘一'},{name:'二楞'}])
+db.users.insertMany([{name:'缘一1'},{name:'二楞1'}])
+db.getCollection('users').insertMany([{name:'zhang3',age:19},{name:'zhang4',age:19}])
  • 脚本方式
shell
for(let i =0;i<5;i++){ 
+	db.users.insert({id:i,name:'zhang'+i})
+}
for(let i =0;i<5;i++){ 
+	db.users.insert({id:i,name:'zhang'+i})
+}

3.删除

shell
db.users.remove({}) 	#删除所有文档
+db.users.remove({_id:ObjectId("62767f841f41a9d7de748124")})	 #删除某一条
+db.users.remove({age:20})	 #删除满足条件的数据
+
+db.getCollection('users').deleteOne({name:'zhang3'})	 #删除某一条
+db.getCollection('users').deleteMany({age:18})	 #删除满足条件的数据
db.users.remove({}) 	#删除所有文档
+db.users.remove({_id:ObjectId("62767f841f41a9d7de748124")})	 #删除某一条
+db.users.remove({age:20})	 #删除满足条件的数据
+
+db.getCollection('users').deleteOne({name:'zhang3'})	 #删除某一条
+db.getCollection('users').deleteMany({age:18})	 #删除满足条件的数据

4.更新

语法 :

js
db.集合名称.update(
+	<query>,
+    <update>,
+    {
+        updert:<boolean>, 
+        multi:<boolean>,
+    	writeConcern:<document> //抛出异常的级别
+    }
+)
db.集合名称.update(
+	<query>,
+    <update>,
+    {
+        updert:<boolean>, 
+        multi:<boolean>,
+    	writeConcern:<document> //抛出异常的级别
+    }
+)
shell
db.users.update({_id:ObjectId('627686574f57a31b328b63ab')},{$set:{age:24,likes:['代码','吃饭']}})  #指定更新
+db.users.update({age:18},{$set:{age:24,likes:['动漫','美女']}})  #更新匹配到的第一条
+db.users.update(
+    {age:18},
+    {$set:{age:24,likes:['动漫','美女']}},
+    {multi:true} 	#更新多条
+    {upsert:true} 	#不存在则插入
+)  #更新匹配到的所有
+
+db.getCollection('users').update({age:18},{$set:{age:24,likes:['动漫','美女']}})	#更新匹配到的第一条
db.users.update({_id:ObjectId('627686574f57a31b328b63ab')},{$set:{age:24,likes:['代码','吃饭']}})  #指定更新
+db.users.update({age:18},{$set:{age:24,likes:['动漫','美女']}})  #更新匹配到的第一条
+db.users.update(
+    {age:18},
+    {$set:{age:24,likes:['动漫','美女']}},
+    {multi:true} 	#更新多条
+    {upsert:true} 	#不存在则插入
+)  #更新匹配到的所有
+
+db.getCollection('users').update({age:18},{$set:{age:24,likes:['动漫','美女']}})	#更新匹配到的第一条

五、Mongoose学习

1.插入

js
exports.register = async (req,res,next)=>{
+  try {
+     let user = new User(req.body.user)
+     await user.save() 
+     //转化为json才能移除密码
+     user = user.toJSON()
+     delete user.password
+     res.send({
+       msg:'注册成功!',
+       user
+     });
+  } catch (error) {
+    next(error)
+  }
+}
exports.register = async (req,res,next)=>{
+  try {
+     let user = new User(req.body.user)
+     await user.save() 
+     //转化为json才能移除密码
+     user = user.toJSON()
+     delete user.password
+     res.send({
+       msg:'注册成功!',
+       user
+     });
+  } catch (error) {
+    next(error)
+  }
+}

2.删除

js
exports.deleteArticle = async (req,res,next)=>{
+  try {
+    let id = mongoose.Types.ObjectId(req.body.id)
+    const result = await Article.findByIdAndRemove(id)
+    console.log('result: ', result);
+    res.succ({
+      msg:'文章删除成功!'
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
exports.deleteArticle = async (req,res,next)=>{
+  try {
+    let id = mongoose.Types.ObjectId(req.body.id)
+    const result = await Article.findByIdAndRemove(id)
+    console.log('result: ', result);
+    res.succ({
+      msg:'文章删除成功!'
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}

3.更新

js
exports.updateArticle =async (req,res,next)=>{
+  const article = req.body.article
+  try {
+    let {_id:id,title,desc,body,tagList} = req.body.article 
+    
+    let article  = await  Article.findByIdAndUpdate(id, { $set:req.body.article},  {new:true})
+      res.succ({
+        msg:'文章更新成功!',
+        article:article
+      })
+  } catch (error) {
+    res.errs(error)
+  }
+}
exports.updateArticle =async (req,res,next)=>{
+  const article = req.body.article
+  try {
+    let {_id:id,title,desc,body,tagList} = req.body.article 
+    
+    let article  = await  Article.findByIdAndUpdate(id, { $set:req.body.article},  {new:true})
+      res.succ({
+        msg:'文章更新成功!',
+        article:article
+      })
+  } catch (error) {
+    res.errs(error)
+  }
+}

4.查询

js
//获取一个文章
+
+exports.getArticleById = async (req,res,next)=>{
+  try {
+      //映射用户
+    const article = await Article.findById(req.params.articleId).populate('author')
+    if(!article){
+     return  res.errs('文章不存在!')
+    }
+    res.succ({
+      msg:'文章查询成功!',
+      article
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
//获取一个文章
+
+exports.getArticleById = async (req,res,next)=>{
+  try {
+      //映射用户
+    const article = await Article.findById(req.params.articleId).populate('author')
+    if(!article){
+     return  res.errs('文章不存在!')
+    }
+    res.succ({
+      msg:'文章查询成功!',
+      article
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
js
// 获取文章列表
+exports.getArticles = async (req,res,next)=>{
+  try {
+   const {limit=20,offset=0,tag ,author,favorited,sortBy}  = req.body.conditions  || {}
+    const filter = {}
+    if(tag){
+      filter.tagList = tag
+    }
+    //某个作者的文章
+    if(author){
+      const user = await User.findOne({username:author})
+        filter.author =user? user._id:null;
+    }
+    const articleList = await Article.find(filter).skip(Number.parseInt(offset))
+    .limit(Number.parseInt(limit)).sort({creeateAt:-1,...sortBy})
+
+    const articleCount = await Article.find(filter).skip(offset).limit(limit).count()
+    const totalCount = await Article.countDocuments()
+    if(!articleList){
+     return  res.errs('暂无文章!')
+    }
+    res.succ({
+      msg:'文章查询列表成功!',
+      articleList,
+      articleCount,
+      totalCount
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
// 获取文章列表
+exports.getArticles = async (req,res,next)=>{
+  try {
+   const {limit=20,offset=0,tag ,author,favorited,sortBy}  = req.body.conditions  || {}
+    const filter = {}
+    if(tag){
+      filter.tagList = tag
+    }
+    //某个作者的文章
+    if(author){
+      const user = await User.findOne({username:author})
+        filter.author =user? user._id:null;
+    }
+    const articleList = await Article.find(filter).skip(Number.parseInt(offset))
+    .limit(Number.parseInt(limit)).sort({creeateAt:-1,...sortBy})
+
+    const articleCount = await Article.find(filter).skip(offset).limit(limit).count()
+    const totalCount = await Article.countDocuments()
+    if(!articleList){
+     return  res.errs('暂无文章!')
+    }
+    res.succ({
+      msg:'文章查询列表成功!',
+      articleList,
+      articleCount,
+      totalCount
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}

5.模型

📝model/index.js

js
const mongoose = require('mongoose');
+const { dbUri  } = require('../config/config.default')
+mongoose.connect(dbUri);
+
+const db = mongoose.connection;
+
+db.on('error', console.error.bind(console, 'MongDB数据库连接失败!'));
+
+db.once('open', function() {
+  console.log('MongDB数据库连接成功!');
+});
+const Cat = mongoose.model('Cat', { name: String });
+
+module.exports = {
+  User:mongoose.model('User',require('./user')),
+  Article:mongoose.model('Article',require('./article')),
+}
const mongoose = require('mongoose');
+const { dbUri  } = require('../config/config.default')
+mongoose.connect(dbUri);
+
+const db = mongoose.connection;
+
+db.on('error', console.error.bind(console, 'MongDB数据库连接失败!'));
+
+db.once('open', function() {
+  console.log('MongDB数据库连接成功!');
+});
+const Cat = mongoose.model('Cat', { name: String });
+
+module.exports = {
+  User:mongoose.model('User',require('./user')),
+  Article:mongoose.model('Article',require('./article')),
+}

📝model/base.js

js
//基础模型 
+module.exports =  {
+  createAt:{
+    type:Date,
+    default:Date.now
+  },
+  updtedAt:{
+    type:Date,
+    default:Date.now
+  }
+}
//基础模型 
+module.exports =  {
+  createAt:{
+    type:Date,
+    default:Date.now
+  },
+  updtedAt:{
+    type:Date,
+    default:Date.now
+  }
+}

📝model/user.js

js

+const mongoose =  require('mongoose')
+const baseSchema = require('./base')
+const md5 = require('../util/md5')
+//用户模型
+const userSchema = new mongoose.Schema({
+  ...baseSchema,
+  username:{
+    type:String,
+    required:true
+  },
+  password:{
+    type:String,
+    required:true,
+    set:value => md5(value),
+    select:false,
+  },
+  email:{
+    type:String,
+    required:true
+  },
+  bio:{
+    type:String,
+    default:null
+  },
+  image:{
+    type:String,
+    default:null
+  },
+  
+})
+module.exports = userSchema

+const mongoose =  require('mongoose')
+const baseSchema = require('./base')
+const md5 = require('../util/md5')
+//用户模型
+const userSchema = new mongoose.Schema({
+  ...baseSchema,
+  username:{
+    type:String,
+    required:true
+  },
+  password:{
+    type:String,
+    required:true,
+    set:value => md5(value),
+    select:false,
+  },
+  email:{
+    type:String,
+    required:true
+  },
+  bio:{
+    type:String,
+    default:null
+  },
+  image:{
+    type:String,
+    default:null
+  },
+  
+})
+module.exports = userSchema

📝model/article.js

js
 const mongoose =  require('mongoose')
+const Schema = mongoose.Schema
+const baseSchema = require('./base')
+//文章模型
+const articleSchema = new mongoose.Schema({
+  ...baseSchema,
+  title:{
+    type:String,
+    required:true
+  },
+  desc:{
+    type:String,
+    required:true
+  },
+  body:{
+    type:String,
+    required:true
+  },
+  favoritesCount:{
+    type:Number,
+    default:0
+  },
+  tagList:{
+    type:[String],
+    default:null
+  },
+   author:{
+     type:Schema.Types.ObjectId,
+     ref:'User',
+     required:true,
+   }
+})
+module.exports = articleSchema
 const mongoose =  require('mongoose')
+const Schema = mongoose.Schema
+const baseSchema = require('./base')
+//文章模型
+const articleSchema = new mongoose.Schema({
+  ...baseSchema,
+  title:{
+    type:String,
+    required:true
+  },
+  desc:{
+    type:String,
+    required:true
+  },
+  body:{
+    type:String,
+    required:true
+  },
+  favoritesCount:{
+    type:Number,
+    default:0
+  },
+  tagList:{
+    type:[String],
+    default:null
+  },
+   author:{
+     type:Schema.Types.ObjectId,
+     ref:'User',
+     required:true,
+   }
+})
+module.exports = articleSchema
+ + + + \ No newline at end of file diff --git "a/BackEnd/NodeJS/Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.html" "b/BackEnd/NodeJS/Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.html" new file mode 100644 index 00000000..89e8f3c0 --- /dev/null +++ "b/BackEnd/NodeJS/Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.html" @@ -0,0 +1,277 @@ + + + + + + Node大文件上传 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Node大文件上传

  1. 创建文件唯一 HASH
  2. 发请求检查文件是否已传过
    1. 传过:提示'秒传成功'
    2. 未传过:开始切片并上传,创建任务池,循环上传切片
    3. 传过未传完:从下一切片开始传
  3. 上传完成,发送合并切片请求

Vue 前端代码

vue
<template>
+  <el-upload :http-request="customRequest">
+    <template #trigger>
+      <el-button type="primary">选择文件</el-button>
+    </template>
+  </el-upload>
+</template>
+<script lang="ts" setup>
+import axios from 'axios';
+import SparkMD5 from 'spark-md5'
+const customRequest = async ({ file }) => {
+  const formData = new FormData()
+  formData.append('fileName', file)
+  const hash = await calcFileHash(file)
+  const chunks = createFileChunk(file, hash)
+  // 检查文件是否存在
+  // const { data: { data: { exist } } } = await checkFileExist(hash)
+  const res = await uploadChunks(chunks, hash)
+}
+const checkFileExist = (hash) => {
+  return axios.post('http://localhost:3000/upload/checkFile', {
+    hash
+  })
+}
+type Chunk = {
+  name: string
+  index: number
+  chunk: Blob
+  hash: string
+}
+const ChunkSize = 1024 * 1024 * 2 // 2M
+// 创建分片
+const createFileChunk = (file, hash) => {
+  const chunks: Chunk[] = []
+  const chunkCount = Math.ceil(file.size / ChunkSize)
+  for (let i = 0; i < chunkCount; i++) {
+    const chunk: Blob = file.slice(i * ChunkSize, (i + 1) * ChunkSize)
+    const name = hash + "-" + i + "." + file.name.substring(file.name.lastIndexOf(".") + 1)
+    chunks.push({
+      name,
+      index: i,
+      chunk,
+      hash,
+    })
+  }
+  return chunks
+}
+// 创建文件hash值
+const calcFileHash = (file: File) => {
+  return new Promise(resolve => {
+    const spark = new SparkMD5.ArrayBuffer()
+    const reader = new FileReader()
+    const size = file.size
+    const offset = 2 * 1024 * 1024
+    // 第一个2M,最后一个区块数据全要
+    const chunks = [file.slice(0, offset)]
+    let cur = offset
+    while (cur < size) {
+      if (cur + offset >= size) {
+        // 最后一个区快
+        chunks.push(file.slice(cur, cur + offset))
+      } else {
+        // 中间的区块
+        const mid = cur + offset / 2
+        const end = cur + offset
+        chunks.push(file.slice(cur, cur + 2))
+        chunks.push(file.slice(mid, mid + 2))
+        chunks.push(file.slice(end - 2, end))
+      }
+      cur += offset
+    }
+    // 中间的,取前中后各2各字节
+    reader.readAsArrayBuffer(new Blob(chunks))
+    reader.onload = e => {
+      spark.append(e?.target?.result as ArrayBuffer)
+      resolve(spark.end())
+    }
+  })
+}
+// 上传分片
+const uploadChunks = async (chunks: Array<Chunk>, hash: string) => {
+  // 转成promise
+  const requestList = chunks.map(({ chunk, name, index, hash }) => {
+    const form = new FormData()
+    form.append('chunk', chunk, name)
+    form.append('hash', hash)
+    form.append('name', name)
+    return { form, index: index, error: 0 }
+  })
+
+  let index = 0
+  const taskPool: Array<Promise<any>> = []
+  const max = 6 // 设置浏览器运行最大并发数  目前6个为当前的主流
+  let allProgress = index // 总进度
+  while (index < requestList.length) {
+    const task = axios.post("http://localhost:3000/upload/postFile", requestList[index].form, {
+      onUploadProgress: (progress) => {
+        allProgress += (progress.loaded / (progress.total ? progress.total : 1)) // 这是单个分片的
+        const percent = ((allProgress / requestList.length) * 100)
+        // if (params.onProgress) params.onProgress({ percent })
+      }
+    })
+    task.then(() => {
+      taskPool.splice(taskPool.findIndex(item => item === task))
+    })
+    taskPool.push(task)
+    if (taskPool.length === max) {
+      await Promise.race(taskPool) // 竞赛等出一个执行完毕的请求
+    }
+    index++
+  }
+  console.log('[ taskPool ]-95', taskPool)
+
+  await Promise.all(taskPool)
+}
+
+
+</script>
+
+<style scoped lang="scss">
+.upload-demo {
+  margin: 100px 100px;
+}
+</style>
<template>
+  <el-upload :http-request="customRequest">
+    <template #trigger>
+      <el-button type="primary">选择文件</el-button>
+    </template>
+  </el-upload>
+</template>
+<script lang="ts" setup>
+import axios from 'axios';
+import SparkMD5 from 'spark-md5'
+const customRequest = async ({ file }) => {
+  const formData = new FormData()
+  formData.append('fileName', file)
+  const hash = await calcFileHash(file)
+  const chunks = createFileChunk(file, hash)
+  // 检查文件是否存在
+  // const { data: { data: { exist } } } = await checkFileExist(hash)
+  const res = await uploadChunks(chunks, hash)
+}
+const checkFileExist = (hash) => {
+  return axios.post('http://localhost:3000/upload/checkFile', {
+    hash
+  })
+}
+type Chunk = {
+  name: string
+  index: number
+  chunk: Blob
+  hash: string
+}
+const ChunkSize = 1024 * 1024 * 2 // 2M
+// 创建分片
+const createFileChunk = (file, hash) => {
+  const chunks: Chunk[] = []
+  const chunkCount = Math.ceil(file.size / ChunkSize)
+  for (let i = 0; i < chunkCount; i++) {
+    const chunk: Blob = file.slice(i * ChunkSize, (i + 1) * ChunkSize)
+    const name = hash + "-" + i + "." + file.name.substring(file.name.lastIndexOf(".") + 1)
+    chunks.push({
+      name,
+      index: i,
+      chunk,
+      hash,
+    })
+  }
+  return chunks
+}
+// 创建文件hash值
+const calcFileHash = (file: File) => {
+  return new Promise(resolve => {
+    const spark = new SparkMD5.ArrayBuffer()
+    const reader = new FileReader()
+    const size = file.size
+    const offset = 2 * 1024 * 1024
+    // 第一个2M,最后一个区块数据全要
+    const chunks = [file.slice(0, offset)]
+    let cur = offset
+    while (cur < size) {
+      if (cur + offset >= size) {
+        // 最后一个区快
+        chunks.push(file.slice(cur, cur + offset))
+      } else {
+        // 中间的区块
+        const mid = cur + offset / 2
+        const end = cur + offset
+        chunks.push(file.slice(cur, cur + 2))
+        chunks.push(file.slice(mid, mid + 2))
+        chunks.push(file.slice(end - 2, end))
+      }
+      cur += offset
+    }
+    // 中间的,取前中后各2各字节
+    reader.readAsArrayBuffer(new Blob(chunks))
+    reader.onload = e => {
+      spark.append(e?.target?.result as ArrayBuffer)
+      resolve(spark.end())
+    }
+  })
+}
+// 上传分片
+const uploadChunks = async (chunks: Array<Chunk>, hash: string) => {
+  // 转成promise
+  const requestList = chunks.map(({ chunk, name, index, hash }) => {
+    const form = new FormData()
+    form.append('chunk', chunk, name)
+    form.append('hash', hash)
+    form.append('name', name)
+    return { form, index: index, error: 0 }
+  })
+
+  let index = 0
+  const taskPool: Array<Promise<any>> = []
+  const max = 6 // 设置浏览器运行最大并发数  目前6个为当前的主流
+  let allProgress = index // 总进度
+  while (index < requestList.length) {
+    const task = axios.post("http://localhost:3000/upload/postFile", requestList[index].form, {
+      onUploadProgress: (progress) => {
+        allProgress += (progress.loaded / (progress.total ? progress.total : 1)) // 这是单个分片的
+        const percent = ((allProgress / requestList.length) * 100)
+        // if (params.onProgress) params.onProgress({ percent })
+      }
+    })
+    task.then(() => {
+      taskPool.splice(taskPool.findIndex(item => item === task))
+    })
+    taskPool.push(task)
+    if (taskPool.length === max) {
+      await Promise.race(taskPool) // 竞赛等出一个执行完毕的请求
+    }
+    index++
+  }
+  console.log('[ taskPool ]-95', taskPool)
+
+  await Promise.all(taskPool)
+}
+
+
+</script>
+
+<style scoped lang="scss">
+.upload-demo {
+  margin: 100px 100px;
+}
+</style>
+ + + + \ No newline at end of file diff --git "a/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.html" "b/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.html" new file mode 100644 index 00000000..d4cc041e --- /dev/null +++ "b/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.html" @@ -0,0 +1,1003 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、读取文件

js
const fs = require('fs')
+fs.readFile('1.txt','utf8',function(err,data){
+
+    console.log('data: ', data);//失败为undefined
+    console.log('err: ', err);//成功为null,否则为错误对象
+
+    if(err){
+	 return console.log('读取失败'+err.message)
+   }
+ console.log('读取成功'+data)
+})
const fs = require('fs')
+fs.readFile('1.txt','utf8',function(err,data){
+
+    console.log('data: ', data);//失败为undefined
+    console.log('err: ', err);//成功为null,否则为错误对象
+
+    if(err){
+	 return console.log('读取失败'+err.message)
+   }
+ console.log('读取成功'+data)
+})

问题

  • 相对路径在上一层读取不了文件
  • 绝对路径不利于维护移植

解决

__dirname代表当前文件所处目录, 解决文件路径动态拼接问题

坑点__dirname输出是路径是**反斜杠(\),拼接后面的路径需要写正斜杠(/)**

js
//__dirname:  D:\PracticeProject\Node\readfile
+
+fs.readFile(__dirname+'/3.txt','utf8',function(err,data){
+    __dirname+'\\\\3.txt',
+    __dirname+'\\\3.txt',
+     __dirname+'\\\3.txt',
+    __dirname+'/\\3.txt',
+   console.log('__dirname: ', __dirname+'\\3.txt');//这四个都可以成功(?)
+
+  console.log('__dirname: ', __dirname);
+    console.log('data: ', data);
+    if(err){
+	    return console.log('读取失败'+err.message)
+   }
+})
//__dirname:  D:\PracticeProject\Node\readfile
+
+fs.readFile(__dirname+'/3.txt','utf8',function(err,data){
+    __dirname+'\\\\3.txt',
+    __dirname+'\\\3.txt',
+     __dirname+'\\\3.txt',
+    __dirname+'/\\3.txt',
+   console.log('__dirname: ', __dirname+'\\3.txt');//这四个都可以成功(?)
+
+  console.log('__dirname: ', __dirname);
+    console.log('data: ', data);
+    if(err){
+	    return console.log('读取失败'+err.message)
+   }
+})

path 路径模块

js
const pathStr = path.join('/a','/b/c','../','/d')  //  a\b\d 抵消路劲(../)
const pathStr = path.join('/a','/b/c','../','/d')  //  a\b\d 抵消路劲(../)

获取文件扩展名

js
const fext = path.extname(fpath)
const fext = path.extname(fpath)

二、写入文件

js
const fs = require('fs')
+fs.writeFile('F:/12.txt','888888',function(err  ){
+
+  if(err){
+    console.log('写入失败 ', err.message);
+  }
+  //写入成功,错误为null
+     console.log('写入成功');
+})
const fs = require('fs')
+fs.writeFile('F:/12.txt','888888',function(err  ){
+
+  if(err){
+    console.log('写入失败 ', err.message);
+  }
+  //写入成功,错误为null
+     console.log('写入成功');
+})

fs.writeFile 只能创建文件,不能创建路径

重复调用 fs.writeFile 写入同一个文件,新写入的会覆盖之前内容

三、服务器操作

服务器与普通电脑:服务器上安装了 web 服务器软件

1.创建 web 服务器步骤

  • 导入 http 模块
  • 创建 web 服务器实例
  • 为服务器实例绑定 request 事件,监听客户端请求
  • 启动服务器
js
const http = require('http')
+const server = http.createServer()
+server.on('request',(req,res)=>{
+    //返回数据给客户端(解决中文乱码两种方法)
+     res.writeHead(200, { "Content-Type": "text/plain;charset=utf-8" });
+    // res.setHeader('Content-Type','text/html; charset=utf-8')
+ 	 res.end('请求url:'+req.url+',请求方法:'+req.method)
+	 console.log('服务器监听到请求')
+})
+server.listen(80,()=>{
+	console.log('服务器运行在 127.0.0.1')
+})
const http = require('http')
+const server = http.createServer()
+server.on('request',(req,res)=>{
+    //返回数据给客户端(解决中文乱码两种方法)
+     res.writeHead(200, { "Content-Type": "text/plain;charset=utf-8" });
+    // res.setHeader('Content-Type','text/html; charset=utf-8')
+ 	 res.end('请求url:'+req.url+',请求方法:'+req.method)
+	 console.log('服务器监听到请求')
+})
+server.listen(80,()=>{
+	console.log('服务器运行在 127.0.0.1')
+})

2.动态响应内容

js
const http = require("http");
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  const url = req.url;
+  let content = `<h1>Not Found 404</h1>`;
+  if (url === "/" || url === "/index.html") {
+    content = `<h1>Home</h1>`;
+  } else if (url === "/about.html") {
+    content = `<h1>About</h1>`;
+  }
+  res.setHeader('Content-Type','text/html; charset=utf-8')
+  res.end(content);
+});
+server.listen(80, () => {
+  console.log("运行在localhost:8080");
+});
const http = require("http");
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  const url = req.url;
+  let content = `<h1>Not Found 404</h1>`;
+  if (url === "/" || url === "/index.html") {
+    content = `<h1>Home</h1>`;
+  } else if (url === "/about.html") {
+    content = `<h1>About</h1>`;
+  }
+  res.setHeader('Content-Type','text/html; charset=utf-8')
+  res.end(content);
+});
+server.listen(80, () => {
+  console.log("运行在localhost:8080");
+});

3.响应文件内容

js
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const fpath = req.url;
+    //映射服务器文件路径
+  fs.readFile(path.join(__dirname, fpath), "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const fpath = req.url;
+    //映射服务器文件路径
+  fs.readFile(path.join(__dirname, fpath), "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});

优化访问方式

js
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const url = req.url
+  let fpath = '';
+
+    //让访问(/,/index.html,/stock-roolup/index.html)都可以得到响应
+  if(url ==='/'){
+    fpath = path.join(__dirname,'/stock-rollup/index.html')
+  }else if(url === '/index.html'){
+    fpath = path.join(__dirname,'/stock-rollup',url)
+  }else if(url === '/stock-rollup/index.html'){
+    fpath = path.join(__dirname, url)
+  }
+  console.log('fpath: ', fpath);
+  fs.readFile(fpath, "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const url = req.url
+  let fpath = '';
+
+    //让访问(/,/index.html,/stock-roolup/index.html)都可以得到响应
+  if(url ==='/'){
+    fpath = path.join(__dirname,'/stock-rollup/index.html')
+  }else if(url === '/index.html'){
+    fpath = path.join(__dirname,'/stock-rollup',url)
+  }else if(url === '/stock-rollup/index.html'){
+    fpath = path.join(__dirname, url)
+  }
+  console.log('fpath: ', fpath);
+  fs.readFile(fpath, "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});

四、Node 模块化

模块分为:内置模块、自定义模块、第三方模块

1.module 对象

在自定义模块中,module.exports模式是空对象,使用module.exports将模块内部成员共享

image-20220430114048249

2.模块共享

m1.js

js
const name = 'zhangsan'
+
+module.exports.name ='lisi'
+console.log('module-m1: ', module);
const name = 'zhangsan'
+
+module.exports.name ='lisi'
+console.log('module-m1: ', module);

m2.js

js
const m1 = require('./m1')
+console.log(m1.name);
const m1 = require('./m1')
+console.log(m1.name);

运行: node m2.js

image-20220430120846611

导出的对象以module.expports为准, 使用require()得到的永远是module.expports指向的对象

js
//m1.js
+exports.name = 'zhangsan'
+exports.age = 18
+
+module.exports={
+  name:'lisi',
+  age:20
+}
+//m2.js
+const m1 = require('./m1')
+console.log(m1.name); //lisi
+console.log(m1.age); //20
//m1.js
+exports.name = 'zhangsan'
+exports.age = 18
+
+module.exports={
+  name:'lisi',
+  age:20
+}
+//m2.js
+const m1 = require('./m1')
+console.log(m1.name); //lisi
+console.log(m1.age); //20

image-20220430121633293

五、模块加载机制

  1. 优先从缓存中加载,模块多次 require()只会执行一次

  2. 内置模块的加载优先级是最高的

  3. 自定义模块 require 时,必须在路径指定./或../开头的路径标识符

image-202205022209230724. 第三方模块记载机制

image-20220502221028461

  1. 目录作为模块

    image-20220502221133208

六、Express 模块

前端两种服务器:

​ Web 网站服务器:专门对外提供 Web 网页资源服务器

​ API 接口服务器:专门对外提供 API 接口服务器

1.Express 创建服务器

js
const express = require('express')
+const app = express()
+
+app.get('/zhj',(req,res)=>{
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
const express = require('express')
+const app = express()
+
+app.get('/zhj',(req,res)=>{
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})

2.Express 中间件

  • 概念

image-20220501095630708

  • 定义与使用全局中间件

    可以调用多个中间件对请求进行**预处理**

    image-20220501095912439

js
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+app.use(mw)
+app.get('/zjj',(req,res)=>{
+  console.log('req.name: ', req.name); //zhangsan
+  console.log('zjj被访问');
+  res.send('zjj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+app.use(mw)
+app.get('/zjj',(req,res)=>{
+  console.log('req.name: ', req.name); //zhangsan
+  console.log('zjj被访问');
+  res.send('zjj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
  • 中间件本质

    next 函数可以流转关系转交给下一个中间件或路由

image-20220501100043506

  • 局部中间件
js

+...
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+//在路由加一个参数,
+app.get('/mw1',mw1,(req,res)=>{
+  console.log('req.age: ', req.age);
+  console.log('mw1被访问');
+  res.send('mw1被访问哈哈哈')
+})
+...

+...
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+//在路由加一个参数,
+app.get('/mw1',mw1,(req,res)=>{
+  console.log('req.age: ', req.age);
+  console.log('mw1被访问');
+  res.send('mw1被访问哈哈哈')
+})
+...
  • 多个局部中间件
js
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+const mw2 = (req,res,next) => {
+  console.log('中间件mw2被执行了');
+  req.age= 20
+  next()
+}
+app.use(mw)
+app.get('/zhj',(req,res)=>{
+  console.log('req.name: ', req.name);
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+//两种传参方式
+app.get('/mw1',[mw1,mw2],(req,res)=>{
+//app.get('/mw1',mw1,mw2,(req,res)=>{
+  console.log('req.age: ', req.age); //20
+  res.send('mw1被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+const mw2 = (req,res,next) => {
+  console.log('中间件mw2被执行了');
+  req.age= 20
+  next()
+}
+app.use(mw)
+app.get('/zhj',(req,res)=>{
+  console.log('req.name: ', req.name);
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+//两种传参方式
+app.get('/mw1',[mw1,mw2],(req,res)=>{
+//app.get('/mw1',mw1,mw2,(req,res)=>{
+  console.log('req.age: ', req.age); //20
+  res.send('mw1被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})

image-20220501101526777

  • 中间件注意事项
  1. 一定要在路由之前注册中间件
  2. 可以连续调用多个中间件对请求进行处理
  3. 中间件函数必须有next()函数
  4. next()后不要写额外代码
  5. 连续调用的多个中间件共享 req 和 res 对象
  • 中间件分类
  1. 应用级别中间件:绑定到 app 实例上的中间件
  2. 路由级别中间件:绑定到 router 实例上的中间件
  3. 错误级别中间件:捕获项目异常错误的中间件

七、编写接口

js
//index.js
+const express = require('express')
+const router = require('./router')
+
+const app = express()
+
+//配置解析urlencoded请求体中间件(在路由中间件前使用)
+app.use(express.urlencoded({extended:false}))
+
+//CORS解决跨域
+const cors = require('cors')
+app.use(cors)
+
+app.use('/api',router)
+
+app.listen(80,()=>{
+  console.log('server running 127.0.0.1:80');
+})
//index.js
+const express = require('express')
+const router = require('./router')
+
+const app = express()
+
+//配置解析urlencoded请求体中间件(在路由中间件前使用)
+app.use(express.urlencoded({extended:false}))
+
+//CORS解决跨域
+const cors = require('cors')
+app.use(cors)
+
+app.use('/api',router)
+
+app.listen(80,()=>{
+  console.log('server running 127.0.0.1:80');
+})
js
//router.js
+const express = require('express')
+const apiRouter = express.Router()
+
+apiRouter.get('/get',(req,res)=>{
+  console.log('req.query: ', req.query);
+  res.send({
+    status:200,
+    message:'GET 请求成功',
+    success:1,
+    data:{
+      name:'zhangsan',
+      age:18
+    }
+  })
+})
+apiRouter.post('/post',(req,res)=>{
+  console.log('req.body',req.body);
+  res.send({
+    status:200,
+    message:'POST 请求成功',
+    success:1,
+    data:req.body
+  })
+})
+
+module.exports = apiRouter
//router.js
+const express = require('express')
+const apiRouter = express.Router()
+
+apiRouter.get('/get',(req,res)=>{
+  console.log('req.query: ', req.query);
+  res.send({
+    status:200,
+    message:'GET 请求成功',
+    success:1,
+    data:{
+      name:'zhangsan',
+      age:18
+    }
+  })
+})
+apiRouter.post('/post',(req,res)=>{
+  console.log('req.body',req.body);
+  res.send({
+    status:200,
+    message:'POST 请求成功',
+    success:1,
+    data:req.body
+  })
+})
+
+module.exports = apiRouter

1. CORS 跨域资源共享

image-20220502115641176

2.CORS 头部

image-20220502120846061

image-20220502120941415

image-20220502121028306

image-20220502121159109

image-20220502120738921

八、Node 连接数据库

1.配置 mysql 模块

  • 安装 mysql 模块:`npm i mysql

  • 连接数据库并测试 mysql 是否连接成功

js
const mysql = require('mysql')
+
+const db = mysql.createPool({
+  host:'127.0.0.1',
+  user:'root',
+  password:'root',
+  database:'mydb01'
+})
+
+//测试
+db.query('select 1',(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res); //res:  [ RowDataPacket { '1': 1 } ]
+})
const mysql = require('mysql')
+
+const db = mysql.createPool({
+  host:'127.0.0.1',
+  user:'root',
+  password:'root',
+  database:'mydb01'
+})
+
+//测试
+db.query('select 1',(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res); //res:  [ RowDataPacket { '1': 1 } ]
+})

2.查询数据

js
//查询语句
+const qstr = 'select * from users'
+db.query(qstr ,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res);
+})
+/*查询结果:
+res:  [
+  RowDataPacket { id: 1, name: '张三', age: 19 },
+  RowDataPacket { id: 2, name: '李四', age: 22 }
+]
+*/
//查询语句
+const qstr = 'select * from users'
+db.query(qstr ,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res);
+})
+/*查询结果:
+res:  [
+  RowDataPacket { id: 1, name: '张三', age: 19 },
+  RowDataPacket { id: 2, name: '李四', age: 22 }
+]
+*/

3.插入数据

js
//方式一:
+let zl = {
+  id:6,
+  name:'zhaoliu',
+  age:21
+}
+//占位符的数量和表的列数需要一致,
+//否则报错ER_WRONG_VALUE_COUNT_ON_ROW: Column count doesn't match value count at row 1
+const istr = `insert into users values(?,?,?)`
+db.query(istr,[zl.id,zl.name,zl.age],(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res:',res);//res.affectedRows大于0表示插入成功
+})
+/* 返回结果:
+res: OkPacket {
+  fieldCount: 0,
+  affectedRows: 1,
+  insertId: 3,
+  serverStatus: 2,
+  warningCount: 0,
+  message: '',
+  protocol41: true,
+  changedRows: 0
+}
+*/
+
+//方式二:(便捷形式)
+const istr = `insert into users set ?`
+db.query(istr,zl,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+ if(res.affectedRows>0){
+     console.log('插入成功',);
+ }
+})
//方式一:
+let zl = {
+  id:6,
+  name:'zhaoliu',
+  age:21
+}
+//占位符的数量和表的列数需要一致,
+//否则报错ER_WRONG_VALUE_COUNT_ON_ROW: Column count doesn't match value count at row 1
+const istr = `insert into users values(?,?,?)`
+db.query(istr,[zl.id,zl.name,zl.age],(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res:',res);//res.affectedRows大于0表示插入成功
+})
+/* 返回结果:
+res: OkPacket {
+  fieldCount: 0,
+  affectedRows: 1,
+  insertId: 3,
+  serverStatus: 2,
+  warningCount: 0,
+  message: '',
+  protocol41: true,
+  changedRows: 0
+}
+*/
+
+//方式二:(便捷形式)
+const istr = `insert into users set ?`
+db.query(istr,zl,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+ if(res.affectedRows>0){
+     console.log('插入成功',);
+ }
+})

4.更新数据

js
//方式一:
+let user = {
+  id: 6,
+  name: "laoqi",
+  age: 30,
+};
+const ustr = `update  users set name=?,age=? where id=?`;
+db.query(ustr, [user.name, user.age, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  console.log("res: ", res);
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});
+//方式二:(便捷形式)
+const ustr = `update  users set ? where id=?`;
+db.query(ustr, [user, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});
//方式一:
+let user = {
+  id: 6,
+  name: "laoqi",
+  age: 30,
+};
+const ustr = `update  users set name=?,age=? where id=?`;
+db.query(ustr, [user.name, user.age, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  console.log("res: ", res);
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});
+//方式二:(便捷形式)
+const ustr = `update  users set ? where id=?`;
+db.query(ustr, [user, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});

5.删除数据

  • 硬删除
js
let dstr = "delete from users where id=?";
+//只有一个占位符可省略数组括号
+db.query(dstr, 6, (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("硬删除成功");
+  }
+});
let dstr = "delete from users where id=?";
+//只有一个占位符可省略数组括号
+db.query(dstr, 6, (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("硬删除成功");
+  }
+});
  • 软删除
js
let user = {
+  id:2,
+  deleted:1
+}
+let dstr  = "update users set ? where id = ?"
+db.query(dstr,[user,user.id],(err,res)=>{
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("软删除成功");
+  }
+})
let user = {
+  id:2,
+  deleted:1
+}
+let dstr  = "update users set ? where id = ?"
+db.query(dstr,[user,user.id],(err,res)=>{
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("软删除成功");
+  }
+})

九、身份认证

1. http 协议的特性

  • 无状态性:多个请求之间相互独立,服务器不会保留每次 HTTP 请求的状态
  • 无连接:服务器挨个处理访问队列里的访问,处理完一个就关闭连接
  • 自动发送
  • 域名独立
  • 过期时限
  • 4KB 限制

注意:Cookie 不具有安全性,可以伪造,所以不要用 Cookie 保存隐私数据。

3.Session 认证

image-20220502193259029

js
const express = require('express')
+const app = express()
+
+//配置 Session 中间件
+const session = require('express-session')
+app.use(
+  session({
+    secret: 'usersession',
+    resave: false,
+    saveUninitialized: true,
+  })
+)
+
+// 托管静态页面
+app.use(express.static('./pages'))
+// 解析 POST 提交过来的表单数据
+app.use(express.urlencoded({ extended: false }))
+
+// 登录的 API 接口
+app.post('/api/login', (req, res) => {
+  // 判断用户提交的登录信息是否正确
+  if (req.body.username !== 'admin' || req.body.password !== '000000') {
+    return res.send({ status: 1, msg: '登录失败' })
+  }
+
+  //将登录成功后的用户信息,保存到 Session 中(express-session配置后才有)
+  req.session.user = req.body // 用户的信息
+  req.session.islogin = true // 用户的登录状态
+
+  res.send({ status: 0, msg: '登录成功' })
+})
+
+// 获取用户姓名的接口
+app.get('/api/username', (req, res) => {
+  //从 Session 中获取用户的名称,响应给客户端
+  if (!req.session.islogin) {
+    return res.send({ status: 1, msg: 'fail' })
+  }
+  res.send({
+    status: 0,
+    msg: 'success',
+    username: req.session.user.username,
+  })
+})
+
+// 退出登录的接口
+app.post('/api/logout', (req, res) => {
+  //清空 Session 信息
+  req.session.destroy()
+  res.send({
+    status: 0,
+    msg: '退出登录成功',
+  })
+})
+
+// 调用 app.listen 方法,指定端口号并启动web服务器
+app.listen(80, function () {
+  console.log('Express server running at http://127.0.0.1:80')
+})
const express = require('express')
+const app = express()
+
+//配置 Session 中间件
+const session = require('express-session')
+app.use(
+  session({
+    secret: 'usersession',
+    resave: false,
+    saveUninitialized: true,
+  })
+)
+
+// 托管静态页面
+app.use(express.static('./pages'))
+// 解析 POST 提交过来的表单数据
+app.use(express.urlencoded({ extended: false }))
+
+// 登录的 API 接口
+app.post('/api/login', (req, res) => {
+  // 判断用户提交的登录信息是否正确
+  if (req.body.username !== 'admin' || req.body.password !== '000000') {
+    return res.send({ status: 1, msg: '登录失败' })
+  }
+
+  //将登录成功后的用户信息,保存到 Session 中(express-session配置后才有)
+  req.session.user = req.body // 用户的信息
+  req.session.islogin = true // 用户的登录状态
+
+  res.send({ status: 0, msg: '登录成功' })
+})
+
+// 获取用户姓名的接口
+app.get('/api/username', (req, res) => {
+  //从 Session 中获取用户的名称,响应给客户端
+  if (!req.session.islogin) {
+    return res.send({ status: 1, msg: 'fail' })
+  }
+  res.send({
+    status: 0,
+    msg: 'success',
+    username: req.session.user.username,
+  })
+})
+
+// 退出登录的接口
+app.post('/api/logout', (req, res) => {
+  //清空 Session 信息
+  req.session.destroy()
+  res.send({
+    status: 0,
+    msg: '退出登录成功',
+  })
+})
+
+// 调用 app.listen 方法,指定端口号并启动web服务器
+app.listen(80, function () {
+  console.log('Express server running at http://127.0.0.1:80')
+})

Session 认证弊端:需要配合 Cookie,Cookie 不支持跨域,需要做额外配置,才能实现跨域 Session 认证。

4.JWT 认证

原理:服务端通多用户信息生成 Token,发送并保存在客户端,服务器通过还原 Token 来认证用户身份。

image-20220502195232085

JWT 组成部分:Header(头部)、Payload(有效载荷)、Signature(签名)。形式:Header.Payload.Signature

image-20220502195537066

JWT 使用

安装jsonwebtokenexpress-jwt

js
const express = require('express')
+const app = express()
+
+// 01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
+const jwt = require('jsonwebtoken')
+const expressJWT = require('express-jwt')
+
+// 允许跨域资源共享
+const cors = require('cors')
+app.use(cors())
+
+// 解析 post 表单数据的中间件
+const bodyParser = require('body-parser')
+app.use(bodyParser.urlencoded({ extended: false }))
+
+// 02:定义 secret 密钥,建议将密钥命名为 secretKey
+const secretKey = 'coder8888'
+
+// 04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
+// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
+app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
+
+// 登录接口
+app.post('/api/login', function (req, res) {
+  // 将 req.body 请求体中的数据,转存为 userinfo 常量
+  const userinfo = req.body
+  // 登录失败
+  if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
+    return res.send({
+      status: 400,
+      message: '登录失败!',
+    })
+  }
+  // 登录成功
+  /* 03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
+   参数1:用户的信息对象
+   参数2:加密的秘钥
+   参数3:配置对象,可以配置当前 token 的有效期
+   记住:千万不要把密码加密到 token 字符中*/
+  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
+  res.send({
+    status: 200,
+    message: '登录成功!',
+    token: tokenStr, // 要发送给客户端的 token 字符串
+  })
+})
+
+// 这是一个有权限的 API 接口
+app.get('/admin/getinfo', function (req, res) {
+  // 05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
+  console.log(req.user)
+  res.send({
+    status: 200,
+    message: '获取用户信息成功!',
+    data: req.user, // 要发送给客户端的用户信息
+  })
+})
+
+// 06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
+app.use((err, req, res, next) => {
+  // 这次错误是由 token 解析失败导致的
+  if (err.name === 'UnauthorizedError') {
+    return res.send({
+      status: 401,
+      message: '无效的token',
+    })
+  }
+  res.send({
+    status: 500,
+    message: '未知的错误',
+  })
+})
+
+
+app.listen(8888, function () {
+  console.log('Express server running at http://127.0.0.1:8888')
+})
const express = require('express')
+const app = express()
+
+// 01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
+const jwt = require('jsonwebtoken')
+const expressJWT = require('express-jwt')
+
+// 允许跨域资源共享
+const cors = require('cors')
+app.use(cors())
+
+// 解析 post 表单数据的中间件
+const bodyParser = require('body-parser')
+app.use(bodyParser.urlencoded({ extended: false }))
+
+// 02:定义 secret 密钥,建议将密钥命名为 secretKey
+const secretKey = 'coder8888'
+
+// 04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
+// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
+app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
+
+// 登录接口
+app.post('/api/login', function (req, res) {
+  // 将 req.body 请求体中的数据,转存为 userinfo 常量
+  const userinfo = req.body
+  // 登录失败
+  if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
+    return res.send({
+      status: 400,
+      message: '登录失败!',
+    })
+  }
+  // 登录成功
+  /* 03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
+   参数1:用户的信息对象
+   参数2:加密的秘钥
+   参数3:配置对象,可以配置当前 token 的有效期
+   记住:千万不要把密码加密到 token 字符中*/
+  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
+  res.send({
+    status: 200,
+    message: '登录成功!',
+    token: tokenStr, // 要发送给客户端的 token 字符串
+  })
+})
+
+// 这是一个有权限的 API 接口
+app.get('/admin/getinfo', function (req, res) {
+  // 05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
+  console.log(req.user)
+  res.send({
+    status: 200,
+    message: '获取用户信息成功!',
+    data: req.user, // 要发送给客户端的用户信息
+  })
+})
+
+// 06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
+app.use((err, req, res, next) => {
+  // 这次错误是由 token 解析失败导致的
+  if (err.name === 'UnauthorizedError') {
+    return res.send({
+      status: 401,
+      message: '无效的token',
+    })
+  }
+  res.send({
+    status: 500,
+    message: '未知的错误',
+  })
+})
+
+
+app.listen(8888, function () {
+  console.log('Express server running at http://127.0.0.1:8888')
+})
+ + + + \ No newline at end of file diff --git "a/BackEnd/NodeJS/Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.html" "b/BackEnd/NodeJS/Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.html" new file mode 100644 index 00000000..fafe1add --- /dev/null +++ "b/BackEnd/NodeJS/Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.html" @@ -0,0 +1,175 @@ + + + + + + Node 简单上传文件 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Node 简单上传文件

Vue 前端代码

vue
<script setup>
+import axios from 'axios'
+const onUpload = (e) => {
+  let formData = new FormData()
+  formData.append('fileName', e.target.files[0]) //fileName:后端接收的参数名
+  console.log('[ formData ]-6', formData)
+  axios.post('http://localhost:3000/upload/postFile', formData, {
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  }).then(res => {
+    console.log('[ res ]', res)
+  }).catch(err => {
+    console.log('[ err ]', err)
+  })
+}
+</script>
+
+<template>
+  <input type="file" @change="onUpload">
+</template>
<script setup>
+import axios from 'axios'
+const onUpload = (e) => {
+  let formData = new FormData()
+  formData.append('fileName', e.target.files[0]) //fileName:后端接收的参数名
+  console.log('[ formData ]-6', formData)
+  axios.post('http://localhost:3000/upload/postFile', formData, {
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  }).then(res => {
+    console.log('[ res ]', res)
+  }).catch(err => {
+    console.log('[ err ]', err)
+  })
+}
+</script>
+
+<template>
+  <input type="file" @change="onUpload">
+</template>

Express 后端代码

js
const express = require("express");
+const multer = require("multer");
+const fs = require("fs");
+const path = require("path");
+
+const app = express();
+const router = express.Router();
+app.use("/upload", router);
+
+const upload = multer({
+  storage: multer.diskStorage({
+    //设置文件存储位置
+    destination: (req, file, cb) => {
+      let date = new Date();
+      let year = date.getFullYear();
+      let month = (date.getMonth() + 1).toString().padStart(2, "0");
+      let day = date.getDate();
+      let dir = "./public/uploads/" + year + month + day;
+      //判断目录是否存在,没有则创建
+      if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
+      //dir就是上传文件存放的目录
+      cb(null, dir);
+    }, //设置文件名称
+    filename: (req, file, cb) => {
+      // 获取原来的文件名
+      let oldName = file.originalname;
+      //获取文件前缀
+      let prefix = oldName.startsWith(".") ? oldName : oldName.split(".")[0];
+      let fileName =
+        prefix + "-" + Date.now() + path.extname(file.originalname);
+      //fileName就是上传文件的文件名
+      cb(null, fileName);
+    },
+  }),
+});
+ //访问地址为:localhost:3000/upload/index,操作界面,使用 Vue 时可不需要这个接口
+router.get("/index", (req, res) => {
+  //接口地址为:localhost:3000/upload/postFile ,input的name属性值为imgFile和upload.single("imgFile")对应
+  res.send(`
+  <form action="http://localhost:3000/upload/postFile" method="post" enctype="multipart/form-data">
+  <input id="postFile" type="file" name="fileName" multiple>
+  <button type="submit">上传</button>
+</form>`);
+});
+router.post("/postFile", upload.single("fileName"), (req, res, next) => {
+  res.json({
+    file: req.file,
+  });
+});
+
+app.listen(3000, () => {
+  console.log("server is running at http://localhost:3000");
+});
const express = require("express");
+const multer = require("multer");
+const fs = require("fs");
+const path = require("path");
+
+const app = express();
+const router = express.Router();
+app.use("/upload", router);
+
+const upload = multer({
+  storage: multer.diskStorage({
+    //设置文件存储位置
+    destination: (req, file, cb) => {
+      let date = new Date();
+      let year = date.getFullYear();
+      let month = (date.getMonth() + 1).toString().padStart(2, "0");
+      let day = date.getDate();
+      let dir = "./public/uploads/" + year + month + day;
+      //判断目录是否存在,没有则创建
+      if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
+      //dir就是上传文件存放的目录
+      cb(null, dir);
+    }, //设置文件名称
+    filename: (req, file, cb) => {
+      // 获取原来的文件名
+      let oldName = file.originalname;
+      //获取文件前缀
+      let prefix = oldName.startsWith(".") ? oldName : oldName.split(".")[0];
+      let fileName =
+        prefix + "-" + Date.now() + path.extname(file.originalname);
+      //fileName就是上传文件的文件名
+      cb(null, fileName);
+    },
+  }),
+});
+ //访问地址为:localhost:3000/upload/index,操作界面,使用 Vue 时可不需要这个接口
+router.get("/index", (req, res) => {
+  //接口地址为:localhost:3000/upload/postFile ,input的name属性值为imgFile和upload.single("imgFile")对应
+  res.send(`
+  <form action="http://localhost:3000/upload/postFile" method="post" enctype="multipart/form-data">
+  <input id="postFile" type="file" name="fileName" multiple>
+  <button type="submit">上传</button>
+</form>`);
+});
+router.post("/postFile", upload.single("fileName"), (req, res, next) => {
+  res.json({
+    file: req.file,
+  });
+});
+
+app.listen(3000, () => {
+  console.log("server is running at http://localhost:3000");
+});

可以借助接口调试工具测试或直接访问:http://localhost:3000/upload/index

image-20230213141712478

image-20230213141820443

+ + + + \ No newline at end of file diff --git "a/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.html" "b/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.html" new file mode 100644 index 00000000..b64a5514 --- /dev/null +++ "b/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.html" @@ -0,0 +1,251 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、解决痛点

  1. 环境不一致
  2. 版本不一样
  3. 配置不一致,配置费力费时

把源码+配置+环境+版本打包成镜像,装载在Dokcer容器引擎上,达到跨平台无缝接轨运作。 一次镜像,处处运行,从搬家到搬楼。

二、优点和应用

  1. 便捷升级和快速扩容
  2. 更简单的系统运维
  3. 镜像小、更高效的计算资源
  4. 更快的应用交付和平缓迁移
  5. 利用宿主机内核,不需要加载操作系统OS内核

三、基本组成

  1. 镜像:一个只读的模板,用于创建容器,一个镜像可以创建多个容器。
  2. 容器:镜像创建出来的虚拟化运行环境容器实例(简易的Linux环境)。
  3. 仓库:集中存放镜像的场所,分为公开库和私有库。

四、工作原理

五、CentOS安装Docker

bash
sudo yum install -y yum-utils
+yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
+sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
+docker version
+systemctl start docker #启动
+ps -ef | grep docker
+docker run hello-world #测试
sudo yum install -y yum-utils
+yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
+sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
+docker version
+systemctl start docker #启动
+ps -ef | grep docker
+docker run hello-world #测试

六、阿里云镜像加速

参考教程

七、常用命令

1. Docker

bash
systemctl enable docker #开机启动
+docker system df #负载查看
systemctl enable docker #开机启动
+docker system df #负载查看

2. 镜像

bash
docker images #展示本地镜像 -a 所有,-q只显示ID
+docker search mongo #搜索镜像
+docker search redis --limit 5 #展示Stars排名前五条
+docker pull 镜像名[:TAG]  #下载镜像,没有版本号默认最新
+docker rmi -f hello-world #强制删除镜像
docker images #展示本地镜像 -a 所有,-q只显示ID
+docker search mongo #搜索镜像
+docker search redis --limit 5 #展示Stars排名前五条
+docker pull 镜像名[:TAG]  #下载镜像,没有版本号默认最新
+docker rmi -f hello-world #强制删除镜像

虚悬镜像:构建或删除过程中产生的仓库名和标签都为none的镜像,没啥用建议删除 docker image ls -f dangling=true 删除:docker image prune

生成新镜像

bash
agt-get update
+apt-get -y install vim
+docker commit -m="vim is ok" -a="fxj" 容器id myubt:1.1
agt-get update
+apt-get -y install vim
+docker commit -m="vim is ok" -a="fxj" 容器id myubt:1.1

本地镜像推送到阿里云

bash
#发布和拉取
+docker login --username=yunzhishangfxj registry.cn-hangzhou.aliyuncs.com
+docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker push registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker run -it registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:1.1  /bin/bash #记得带版本
#发布和拉取
+docker login --username=yunzhishangfxj registry.cn-hangzhou.aliyuncs.com
+docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker push registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker run -it registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:1.1  /bin/bash #记得带版本

3. 容器

bash
docker ps #列出正在运行容器 -a -s
+docker run -it --name="ub01"  ubuntu /bin/bash 
+#-p: 外部主机端口:docker容器端口 -P:随机分配主机端口映射到内部容器端口
+#-i:交互式 -t:输出伪终端 -d:后台运行 --name="容器名" /bin/bash:指定命令解释器
+
+exit #退出,ctrl+q+p:退出但不停止
+docker exec -it 容器id /bin/bash #重新进容器,exit退出不会停止容器
+
+docker start 容器id或容器名
+docker restart 
+docker stop
+docker kill #强制停止
+
+docker rm 容器id或容器名 #删除已停止容器 、未停止 -f 强制删除
+docker rm 
+docker rm -f $(docker ps -a -q) 
+docker ps -a -q | xargs docker rm #一次性删除多个再运行的
docker ps #列出正在运行容器 -a -s
+docker run -it --name="ub01"  ubuntu /bin/bash 
+#-p: 外部主机端口:docker容器端口 -P:随机分配主机端口映射到内部容器端口
+#-i:交互式 -t:输出伪终端 -d:后台运行 --name="容器名" /bin/bash:指定命令解释器
+
+exit #退出,ctrl+q+p:退出但不停止
+docker exec -it 容器id /bin/bash #重新进容器,exit退出不会停止容器
+
+docker start 容器id或容器名
+docker restart 
+docker stop
+docker kill #强制停止
+
+docker rm 容器id或容器名 #删除已停止容器 、未停止 -f 强制删除
+docker rm 
+docker rm -f $(docker ps -a -q) 
+docker ps -a -q | xargs docker rm #一次性删除多个再运行的

启动守护式

bash
docker run -it #前台交互启动
+docker run -d  #后台守护启动
docker run -it #前台交互启动
+docker run -d  #后台守护启动

查看容器日志

bash
docker logs 容器id #查看容器日志
+docker inspect  容器id #查看容器内部细节
docker logs 容器id #查看容器日志
+docker inspect  容器id #查看容器内部细节

容器备份到主机

bash
docker cp 容器id:容器文件路径 目的主机路径  #备份文件
+docker export 容器id > xxx.tar	 #备份整个容器
+cat ub.tar | docker import - 恢复后的镜像名  #从tar包中恢复成镜像
+docker run -it  镜像id /bin/bash #重新恢复容器
docker cp 容器id:容器文件路径 目的主机路径  #备份文件
+docker export 容器id > xxx.tar	 #备份整个容器
+cat ub.tar | docker import - 恢复后的镜像名  #从tar包中恢复成镜像
+docker run -it  镜像id /bin/bash #重新恢复容器

容器卷

八、Dockerfile编写

dockerfile
#基础镜像,基于什么镜像什么版本作为模版 
+From xxx:1.1 
+
+#构建参数,运行时无效,可以构建时候临时修改变量(docker build --build-arg B=10)
+ARG
+
+#定义运行时环境变量,运行时一直生效后续可以引用, ARG变量可以传递给ENV
+ENV NGINX_HOME /usr/local/nginx
+
+#指定进入容器后的默认工作目录(落脚点)
+WORKDIR $NGINX_HOME
+
+#将宿主机的文件拷贝到镜像
+COPY <src>  <dest>
+
+#将主机目录下的文件拷贝到镜像,且会自动处理URL和解压tar压缩包
+ADD 
+
+#Dockerfile构建时运行(docker build), 
+RUN 
+
+#容器启动后(docker run)执行的脚本,多个命令时只会生效最后一个???
+#会被docker run之后的参数替换(/bin/bash)
+CMD  ["/etc/nginx/nginx.conf"]
+
+#类似CMD,但是不会(docker run)后面命令覆盖,而且可以接收CMD传的参数
+ENTRYPOINT ["nginx","-c"] ==> nginx -c /etc/nginx/nginx.conf
+#docker run nginx:test -c /etc/nginx/new.conf ==> nginx -c /etc/nginx/new.conf
+一般语句为:
+FROM WORKDIR COPY-ADD RUN CMD-ENTRYPOINT
+
+
+
+#暴露镜像的指定端口
+EXPOSE 9999
+
+#指定容器卷
+VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
+
+#指定元数据,标识容器便于查找
+LABEL 
+
+#当前镜像构建的时候不会执行,基于当前镜像的镜像去构建的时候才会在FROM后执行
+ONBUILD 
+
+#指定容器使用什么信号,一般指定信号名
+STOPSIGNAL
+
+#检查容易的健康状态
+HEALTHCHECK 
+
+#指定命令解释器 linux为/bin/sh,windows为cmd
+SHELL 
+
+#用于指定RUN CMD等指令运行时的用户身份,不指定是root(用户名:用户组 或 USER 用户id:组id)
+USER
#基础镜像,基于什么镜像什么版本作为模版 
+From xxx:1.1 
+
+#构建参数,运行时无效,可以构建时候临时修改变量(docker build --build-arg B=10)
+ARG
+
+#定义运行时环境变量,运行时一直生效后续可以引用, ARG变量可以传递给ENV
+ENV NGINX_HOME /usr/local/nginx
+
+#指定进入容器后的默认工作目录(落脚点)
+WORKDIR $NGINX_HOME
+
+#将宿主机的文件拷贝到镜像
+COPY <src>  <dest>
+
+#将主机目录下的文件拷贝到镜像,且会自动处理URL和解压tar压缩包
+ADD 
+
+#Dockerfile构建时运行(docker build), 
+RUN 
+
+#容器启动后(docker run)执行的脚本,多个命令时只会生效最后一个???
+#会被docker run之后的参数替换(/bin/bash)
+CMD  ["/etc/nginx/nginx.conf"]
+
+#类似CMD,但是不会(docker run)后面命令覆盖,而且可以接收CMD传的参数
+ENTRYPOINT ["nginx","-c"] ==> nginx -c /etc/nginx/nginx.conf
+#docker run nginx:test -c /etc/nginx/new.conf ==> nginx -c /etc/nginx/new.conf
+一般语句为:
+FROM WORKDIR COPY-ADD RUN CMD-ENTRYPOINT
+
+
+
+#暴露镜像的指定端口
+EXPOSE 9999
+
+#指定容器卷
+VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
+
+#指定元数据,标识容器便于查找
+LABEL 
+
+#当前镜像构建的时候不会执行,基于当前镜像的镜像去构建的时候才会在FROM后执行
+ONBUILD 
+
+#指定容器使用什么信号,一般指定信号名
+STOPSIGNAL
+
+#检查容易的健康状态
+HEALTHCHECK 
+
+#指定命令解释器 linux为/bin/sh,windows为cmd
+SHELL 
+
+#用于指定RUN CMD等指令运行时的用户身份,不指定是root(用户名:用户组 或 USER 用户id:组id)
+USER

九、Docker网络

bash
docker network ls #查看网络
+docker network inspect 网络名 #查看网络源数据
+docker network rm 网络名 #删除网络
+docker network create 网络名 #新建网络
+docker network inspect bridge | grep docker0 #查看网卡信息
+
+# --network 不指定默认就是网桥模式
+#host主机模式(不能指定端口,共享宿主机的ip,没有自己的ip,http://宿主机ip:端口)
+docker run -d --network host --name 容器名 镜像名
+
+docker run -d --network none --name 容器名 镜像名 #只有lo网卡
docker network ls #查看网络
+docker network inspect 网络名 #查看网络源数据
+docker network rm 网络名 #删除网络
+docker network create 网络名 #新建网络
+docker network inspect bridge | grep docker0 #查看网卡信息
+
+# --network 不指定默认就是网桥模式
+#host主机模式(不能指定端口,共享宿主机的ip,没有自己的ip,http://宿主机ip:端口)
+docker run -d --network host --name 容器名 镜像名
+
+docker run -d --network none --name 容器名 镜像名 #只有lo网卡

共用网卡

bash
docker run -d --network container:另一个容器名 --name 容器名 /bin/bash 镜像名  
+#共用的容器关闭,这个容器网卡也没有啦
docker run -d --network container:另一个容器名 --name 容器名 /bin/bash 镜像名  
+#共用的容器关闭,这个容器网卡也没有啦

自定义网络

bash
#启动两个网桥模式容器
+docker run -d -p 8081:8080 --name tomcat81 tomcat
+docker run -d -p 8082:8080 --name tomcat82 tomcat
+
+#两个ip可以相互ping通,痛点:按域名ping不通
#启动两个网桥模式容器
+docker run -d -p 8081:8080 --name tomcat81 tomcat
+docker run -d -p 8082:8080 --name tomcat82 tomcat
+
+#两个ip可以相互ping通,痛点:按域名ping不通
bash
docker run -d -p 8081:8080 --network my_network --name tomcat81 tomcat
+docker run -d -p 8082:8080 --network my_network --name tomcat82 tomcat
+#ip、域名互ping都能通(维护好主机和ip的关系)
docker run -d -p 8081:8080 --network my_network --name tomcat81 tomcat
+docker run -d -p 8082:8080 --network my_network --name tomcat82 tomcat
+#ip、域名互ping都能通(维护好主机和ip的关系)

十、容器编排

意义:集中快速管理多个容器

1. 安装Compose

bash
curl -SL https://github.com/docker/compose/releases/download/v2.14.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
curl -SL https://github.com/docker/compose/releases/download/v2.14.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

2. 常用命令

3. 安装 Portainer

+ + + + \ No newline at end of file diff --git "a/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.html" "b/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.html" new file mode 100644 index 00000000..89515e20 --- /dev/null +++ "b/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.html" @@ -0,0 +1,41 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、Nginx安装

1.安装命令

Ubuntuapt install nginx
CentOS(Red Hat系列)yum install nginx

2.Linux目录结构

3.基础命令

nginx -v/nginx -V查看nginx版本等信息
systemctl start/stop nginx启动/停止nginx
systemctl status nginx查看nginx运行状态
ps -ef | grep nginx查看nginx进程
kill -QUIT 进程号
kill -TERM 进程号从容停止
kill -TERM 进程号
kill -INT 进程号快速停止
pkill -9 nginx强制停止

编写配置

bash
nginx -t	#检查配置文件有没有问题
+grep -Ei  "\{|\}"   nginx.conf #检查配置文件括号配对问题
+nginx -s reload #重载配置
nginx -t	#检查配置文件有没有问题
+grep -Ei  "\{|\}"   nginx.conf #检查配置文件括号配对问题
+nginx -s reload #重载配置

日志分析器

netstat命令

curl命令

CentOS7联网

bash
ip a #查看网卡
+cd /etc/sysconfig/network-scripts
+vi ifcfg-ens160 #把ONBOOT=no ===> 改为yes
+systemctl restart network #重启网络
ip a #查看网卡
+cd /etc/sysconfig/network-scripts
+vi ifcfg-ens160 #把ONBOOT=no ===> 改为yes
+systemctl restart network #重启网络
+ + + + \ No newline at end of file diff --git "a/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" "b/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" new file mode 100644 index 00000000..84ba115f --- /dev/null +++ "b/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" @@ -0,0 +1,381 @@ + + + + + + Angular基础总结一 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Angular基础总结一

一、NgModule

WARNING

被@NgModule所装饰的类被称为angular module

@NgModule元数据

  • declarations —— 该模块的依赖项(该模块用到的组件、指令、管道)。
  • imports —— 导入其他的ngModule。
  • providers —— 提供各种服务。
  • bootstrap —— 根组件,Angular 创建它并插入 index.html 宿主页面

declarations 数组

js
1.模块中使用的组件必须先在declarations 数组中声名
+2.一个组件只能被一个模块声名
+3.在declarations中的组件默认只能在当前模块中使用在其他模块使用必须exports导出
1.模块中使用的组件必须先在declarations 数组中声名
+2.一个组件只能被一个模块声名
+3.在declarations中的组件默认只能在当前模块中使用在其他模块使用必须exports导出

imports 数组

js
1.只会出现在@NgModule装饰器中
+2.模块想要正常工作除了本身的依赖项(declarations)还可能需要其他模块导出的依赖项
+3.只要是angular module都可以导入imports数组中比如ng内置第三方自定义的模块
1.只会出现在@NgModule装饰器中
+2.模块想要正常工作除了本身的依赖项(declarations)还可能需要其他模块导出的依赖项
+3.只要是angular module都可以导入imports数组中比如ng内置第三方自定义的模块

providers 数组

js
该数组为当前模块提供一系列服务
该数组为当前模块提供一系列服务

bootstrap 数组

js
应用是通过引导根模块 AppModule 来启动的引导过程还会创建 bootstrap 数组中列出的组件并把它们逐个插入到浏览器的 DOM 
+该数组中的每个组件都作为组件树的根根组件),后续所有组件都是基于根组件的(如图)
+虽然也可以在宿主页面中放多个组件但是大多数应用只有一个组件树并且只从一个根组件开始引导
+这个根组件通常叫做 AppComponent并且位于根模块的 bootstrap 数组中
应用是通过引导根模块 AppModule 来启动的引导过程还会创建 bootstrap 数组中列出的组件并把它们逐个插入到浏览器的 DOM 
+该数组中的每个组件都作为组件树的根根组件),后续所有组件都是基于根组件的(如图)
+虽然也可以在宿主页面中放多个组件但是大多数应用只有一个组件树并且只从一个根组件开始引导
+这个根组件通常叫做 AppComponent并且位于根模块的 bootstrap 数组中
结构图

二、模板基础语法

1. 模板表达式

模版中还可以写些简单的逻辑,比如判断或运算

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `<h1>{{title}}</h1>
+             <p> sum : {{1 + 1}}</p>
+             <p>price: {{price * 0.7}}</p>
+             <p>与方法结合: {{price * 0.7 + getVal()}}.</p>
+`,    //内联模板
+  styles: [`h1 { color: yellow }`]    //内联样式
+})    
+export class AppComponent {
+  title = 'my-angular-title';
+  price = 30
+  getVal(): number {
+        return 33;
+  }
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `<h1>{{title}}</h1>
+             <p> sum : {{1 + 1}}</p>
+             <p>price: {{price * 0.7}}</p>
+             <p>与方法结合: {{price * 0.7 + getVal()}}.</p>
+`,    //内联模板
+  styles: [`h1 { color: yellow }`]    //内联样式
+})    
+export class AppComponent {
+  title = 'my-angular-title';
+  price = 30
+  getVal(): number {
+        return 33;
+  }
+}

模板表达式遵循原则:

  • 非常简单
  • 执行迅速
  • 没有可见的副作用(即模版中的逻辑不能改变组件的变量)

2. 模板来源

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.scss'] //注意: styleUrls
+})
+export class AppComponent {
+
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.scss'] //注意: styleUrls
+})
+export class AppComponent {
+
+}

3. 属性绑定

html
<img src="../assets/images/zorro.jpg" alt="madao" /><!-- 静态绑定-->
+<img [src]="zorroSrc" alt="zorro" />     <!-- 简写形式-->
+<img bind-src="zorroSrc" alt="zorro" /> <!-- 完整形式-->
+<button [disabled]="isDisabled">click</button>
+<!-- zorroSrc、zorro、isDisabled均为变量 -->
<img src="../assets/images/zorro.jpg" alt="madao" /><!-- 静态绑定-->
+<img [src]="zorroSrc" alt="zorro" />     <!-- 简写形式-->
+<img bind-src="zorroSrc" alt="zorro" /> <!-- 完整形式-->
+<button [disabled]="isDisabled">click</button>
+<!-- zorroSrc、zorro、isDisabled均为变量 -->

4. 自定义属性绑定

html
<p [attr.data-title]="customTitle">一行文字</p>
+<p [attr.title]="customTitle">测试自定义标题属性</p>
<p [attr.data-title]="customTitle">一行文字</p>
+<p [attr.title]="customTitle">测试自定义标题属性</p>

5. 插值表达式属性绑定

html
<img src="{{ picUrl }}" alt="{{ picInfo }}" /> <!-- 不常用 -->
<img src="{{ picUrl }}" alt="{{ picInfo }}" /> <!-- 不常用 -->

6. 单个class样式绑定

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <button type="button" class="btn" [class.btn-primary]="theme === 'primary'">Primary</button>
+      <button type="button" class="btn" [class.btn-secondary]="true">secondary</button>
+      <button type="button" class="btn" [class.btn-success]="isSuccess">success</button>
+      <button type="button" class="btn" [class.btn-danger]="'啦啦啦'">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="0">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="undefined">danger</button>
+    `,
+  styles: []
+})
+export class AppComponent {
+    theme = 'primary';
+    isSuccess = true;
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <button type="button" class="btn" [class.btn-primary]="theme === 'primary'">Primary</button>
+      <button type="button" class="btn" [class.btn-secondary]="true">secondary</button>
+      <button type="button" class="btn" [class.btn-success]="isSuccess">success</button>
+      <button type="button" class="btn" [class.btn-danger]="'啦啦啦'">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="0">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="undefined">danger</button>
+    `,
+  styles: []
+})
+export class AppComponent {
+    theme = 'primary';
+    isSuccess = true;
+}

7. 绑定多个class

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <button type="button" [class]="btnCls">btnCls</button>
+      <button type="button" [class]="btnCls2">btnCls2</button>
+      <button type="button" [class]="btnCls3">btnCls3</button>
+
+      <!-- 也可以用内置指令ngClass -->
+      <button type="button" [ngClass]="btnCls">btnCls</button>
+      <button type="button" [ngClass]="btnCls2">btnCls2</button>
+      <button type="button" [ngClass]="btnCls3">btnCls3</button>
+    `,
+  styles: []
+})
+export class AppComponent {
+    btnCls = 'btn btn-primary';
+    btnCls2 = ['btn', 'btn-success'];
+    btnCls3 = {
+      btn: true,
+      'btn-info': true
+    };
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <button type="button" [class]="btnCls">btnCls</button>
+      <button type="button" [class]="btnCls2">btnCls2</button>
+      <button type="button" [class]="btnCls3">btnCls3</button>
+
+      <!-- 也可以用内置指令ngClass -->
+      <button type="button" [ngClass]="btnCls">btnCls</button>
+      <button type="button" [ngClass]="btnCls2">btnCls2</button>
+      <button type="button" [ngClass]="btnCls3">btnCls3</button>
+    `,
+  styles: []
+})
+export class AppComponent {
+    btnCls = 'btn btn-primary';
+    btnCls2 = ['btn', 'btn-success'];
+    btnCls3 = {
+      btn: true,
+      'btn-info': true
+    };
+}

8. 绑定单个style

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <p [style.color]="'##f60'">一段文字</p>
+      <p [style.height]="'50px'" [style.border]="'1px solid'">设置高度</p>
+      <p [style.height.px]="50" [style.border]="'1px solid'">设置高度</p>
+    `,
+  styles: []
+})
+export class AppComponent {}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <p [style.color]="'##f60'">一段文字</p>
+      <p [style.height]="'50px'" [style.border]="'1px solid'">设置高度</p>
+      <p [style.height.px]="50" [style.border]="'1px solid'">设置高度</p>
+    `,
+  styles: []
+})
+export class AppComponent {}

9. 绑定多个style

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <p [style]="style1">style1</p>
+      <p [style]="style2">style2</p>
+      <p [style]="style3">style3</p>
+
+      <!-- 内置指令ngStyle绑定, 不推荐 -->
+      <!--  <p [ngStyle]="style1">style1</p>-->
+      <!--  <p [ngStyle]="style2">style2</p>-->
+
+      <!-- ngStyle只接收对象 -->
+      <p [ngStyle]="style3">style3</p>
+    `,
+  styles: []
+})
+export class AppComponent {
+  style1 = 'width: 200px;height: 50px;text-align: center;border: 1px solid;';
+  style2 = ['width', '200px', 'height', '50px', 'text-align', 'center', 'border', '1px solid']; // 有问题
+  style3 = {
+    width: '200px',
+    height: '50px',
+    'text-align': 'center',
+    border: '1px solid'
+  };
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <p [style]="style1">style1</p>
+      <p [style]="style2">style2</p>
+      <p [style]="style3">style3</p>
+
+      <!-- 内置指令ngStyle绑定, 不推荐 -->
+      <!--  <p [ngStyle]="style1">style1</p>-->
+      <!--  <p [ngStyle]="style2">style2</p>-->
+
+      <!-- ngStyle只接收对象 -->
+      <p [ngStyle]="style3">style3</p>
+    `,
+  styles: []
+})
+export class AppComponent {
+  style1 = 'width: 200px;height: 50px;text-align: center;border: 1px solid;';
+  style2 = ['width', '200px', 'height', '50px', 'text-align', 'center', 'border', '1px solid']; // 有问题
+  style3 = {
+    width: '200px',
+    height: '50px',
+    'text-align': 'center',
+    border: '1px solid'
+  };

样式优先级

1.某个类或样式绑定越具体,它的优先级就越高

2.绑定总是优先于静态属性

10. 绑定事件

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <button (click)="onClick()">CLICK</button>
+       <button  (click)="onClick1($event)">Primary</button>
+    `,
+  styles: []
+})
+export class AppComponent {
+    onClick() {
+      console.log('onClick');
+    } 
+    onClick1(event: MouseEvent) {
+        console.log('onClick1', event.target);
+    } 
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+      <button (click)="onClick()">CLICK</button>
+       <button  (click)="onClick1($event)">Primary</button>
+    `,
+  styles: []
+})
+export class AppComponent {
+    onClick() {
+      console.log('onClick');
+    } 
+    onClick1(event: MouseEvent) {
+        console.log('onClick1', event.target);
+    } 
+}

11. 输入与输出属性

输入属性:用于父组件传值给子组件(父传子) @Input()

输出属性:用于子组件传值给父组件(子传父)@Output()

输入属性@Input

📝父组件

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+     <app-mycpn [item]="currentItem"></app-mycpn>
+     <!-- <app-mycpn item="我是传入的字符串"></app-mycpn>--> <!--静态属性可不用[]包裹 -->
+
+  `,
+})
+export class AppComponent {
+  currentItem = 'Television';
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+     <app-mycpn [item]="currentItem"></app-mycpn>
+     <!-- <app-mycpn item="我是传入的字符串"></app-mycpn>--> <!--静态属性可不用[]包裹 -->
+
+  `,
+})
+export class AppComponent {
+  currentItem = 'Television';
+}

📝子组件

typescript
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: `<p>
+               Today's item: {{item}}
+             </p>`
+})
+export class MycpnComponent  {
+  @Input() item: string;   
+ //@Input('aliasItem') item: string; 提供别名,item变量只可以在本组件使用
+ //相当于对父组件传入的aliasItem变量进行重命名
+}
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: `<p>
+               Today's item: {{item}}
+             </p>`
+})
+export class MycpnComponent  {
+  @Input() item: string;   
+ //@Input('aliasItem') item: string; 提供别名,item变量只可以在本组件使用
+ //相当于对父组件传入的aliasItem变量进行重命名
+}

输出属性@Output()

📝父组件

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+     <app-mycpn  (newItemEvent)="addItem($event)"></app-mycpn>
+  `,
+})
+export class AppComponent {
+   items = ['item1', 'item2', 'item3', 'item4'];
+    addItem(newItem: string) {
+      this.items.push(newItem);
+    }
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+     <app-mycpn  (newItemEvent)="addItem($event)"></app-mycpn>
+  `,
+})
+export class AppComponent {
+   items = ['item1', 'item2', 'item3', 'item4'];
+    addItem(newItem: string) {
+      this.items.push(newItem);
+    }
+}

📝子组件

typescript
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: `<label>Add an item: <input ##newItem></label>
+             <button (click)="addNewItem(newItem.value)">Add to parent's list</button>`
+})
+export class MycpnComponent  {
+  @Output() newItemEvent = new EventEmitter<string>();
+  // @Output('newItem') newItemEvent = new EventEmitter<string>();
+  addNewItem(value: string) {
+    this.newItemEvent.emit(value);
+  }
+}
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: `<label>Add an item: <input ##newItem></label>
+             <button (click)="addNewItem(newItem.value)">Add to parent's list</button>`
+})
+export class MycpnComponent  {
+  @Output() newItemEvent = new EventEmitter<string>();
+  // @Output('newItem') newItemEvent = new EventEmitter<string>();
+  addNewItem(value: string) {
+    this.newItemEvent.emit(value);
+  }
+}

还可以元数据中声名输入、输出属性。(不推荐)

三、组件样式

宿主选择器

:host选择是是把宿主元素作为目标的唯一方式

md
它选中的是组件模板标签,比如<app-child></app-child>,相当于在父组件的style中使用标签选择器选择 app-child {}
它选中的是组件模板标签,比如<app-child></app-child>,相当于在父组件的style中使用标签选择器选择 app-child {}

当宿主标签上有 active 类名时生效

css
:host(.active) {
+  border-width: 3px solid ##ccc;
+}
:host(.active) {
+  border-width: 3px solid ##ccc;
+}

祖先选择器

当某个祖先元素有 CSS 类 light 时,才会把 background-color 样式应用到组件内部的所有 .title 元素中,找到根元素(html标签)为止

css
:host-context(.light) .title {
+      background-color: ##bfa;
+}
:host-context(.light) .title {
+      background-color: ##bfa;
+}

样式模块化

在 @Component 的元数据中指定的样式只会对该组件的模板生效

组件的样式不会影响到子组件中的模板

组件的样式不会影响到投影内容

视图封装模式

ShadowDom -- 不进不出,没有样式能进来,组件样式出不去, 就自己玩

Emulated --只进不出, 默认选项,全局样式能进来,组件样式出不去

None -- 能进能出,此时组件的样式是全局生效的,注意与其他组件发生样式冲突,(对父组件样式也能生效)

+ + + + \ No newline at end of file diff --git "a/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.html" "b/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.html" new file mode 100644 index 00000000..690986cb --- /dev/null +++ "b/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.html" @@ -0,0 +1,891 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

组件投影

📝shadow.component.html

html
<p>    shadow works!
+    <ng-content select=".head"></ng-content>
+    <ng-content select="[attr-content]"></ng-content>
+    <ng-content select="section"></ng-content>
+</p>
<p>    shadow works!
+    <ng-content select=".head"></ng-content>
+    <ng-content select="[attr-content]"></ng-content>
+    <ng-content select="section"></ng-content>
+</p>

📝app.component.html

html
<!-- 组件投影 -->
+<app-shadow>
+    <p class="head">头部投影内容</p>
+    <section>标签选择器投影内容</section>
+    <p attr-content>自定义属性选择器投影内容</p>
+</app-shadow>
<!-- 组件投影 -->
+<app-shadow>
+    <p class="head">头部投影内容</p>
+    <section>标签选择器投影内容</section>
+    <p attr-content>自定义属性选择器投影内容</p>
+</app-shadow>

🎖️结果展示

ViewChild

📝parent.component.ts

typescript
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+        export class ParentComponent implements OnInit,AfterViewInit {
+
+  // @ViewChild('box',{static:true}) private box:ElementRef //获取dom
+  // @ViewChild(ChildComponent,{static:true}) private instance:ChildComponent  //获取子组件方式一
+  @ViewChild('childcomponent',{static:true}) private childInstance:ChildComponent //获取子组件实例方式二
+
+  constructor() { //执行秩序(1)
+    // console.log('constructor',this.box);
+    // console.log('constructor',this.instance?.childdata);
+    // console.log('constructor',this.childInstance?.childdata);
+    console.log('constructor',this.childInstance);
+
+  }
+  ngOnInit(): void {//(2)
+    // console.log('ngOnInit',this.box.nativeElement);
+    // console.log('ngOnInit',this.instance.childdata);
+    console.log('ngOnInit',this.childInstance);
+    // console.log('ngOnInit',this.childInstance.childdata);
+
+  }
+  ngAfterViewInit(): void { //(3)在变更检测后执行,能保证获取到元素
+    //  console.log('ngAfterViewInit',this.box.nativeElement);
+    //  console.log('ngAfterViewInit',this.instance.childdata);
+     console.log('ngAfterViewInit',this.childInstance.childdata);
+
+  }
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+        export class ParentComponent implements OnInit,AfterViewInit {
+
+  // @ViewChild('box',{static:true}) private box:ElementRef //获取dom
+  // @ViewChild(ChildComponent,{static:true}) private instance:ChildComponent  //获取子组件方式一
+  @ViewChild('childcomponent',{static:true}) private childInstance:ChildComponent //获取子组件实例方式二
+
+  constructor() { //执行秩序(1)
+    // console.log('constructor',this.box);
+    // console.log('constructor',this.instance?.childdata);
+    // console.log('constructor',this.childInstance?.childdata);
+    console.log('constructor',this.childInstance);
+
+  }
+  ngOnInit(): void {//(2)
+    // console.log('ngOnInit',this.box.nativeElement);
+    // console.log('ngOnInit',this.instance.childdata);
+    console.log('ngOnInit',this.childInstance);
+    // console.log('ngOnInit',this.childInstance.childdata);
+
+  }
+  ngAfterViewInit(): void { //(3)在变更检测后执行,能保证获取到元素
+    //  console.log('ngAfterViewInit',this.box.nativeElement);
+    //  console.log('ngAfterViewInit',this.instance.childdata);
+     console.log('ngAfterViewInit',this.childInstance.childdata);
+
+  }

ViewChildren

📝parent.component.html

html
<!-- ViewChildren批量获取元素和组件 -->
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<app-child></app-child>
+<app-child></app-child>
+<app-child></app-child>
<!-- ViewChildren批量获取元素和组件 -->
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<app-child></app-child>
+<app-child></app-child>
+<app-child></app-child>

📝parent.component.ts

typescript
import { AfterViewInit, Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+export class ParentComponent implements OnInit,AfterViewInit {
+
+  // ViewChildren批量获取元素和组件
+  @ViewChildren(ChildComponent) private childs:QueryList<ChildComponent>
+  @ViewChildren('boxs') private childs1:QueryList<ChildComponent>
+  constructor() { 
+  }
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void { //(3)
+     console.log(this.childs);
+     console.log(this.childs1);  //输出QueryList数组 
+      //QueryList中监听子组件变化的回调函数
+     this.childs1.changes.subscribe((changes)=>{
+       console.log(changes);
+
+      })
+  }
+}
import { AfterViewInit, Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+export class ParentComponent implements OnInit,AfterViewInit {
+
+  // ViewChildren批量获取元素和组件
+  @ViewChildren(ChildComponent) private childs:QueryList<ChildComponent>
+  @ViewChildren('boxs') private childs1:QueryList<ChildComponent>
+  constructor() { 
+  }
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void { //(3)
+     console.log(this.childs);
+     console.log(this.childs1);  //输出QueryList数组 
+      //QueryList中监听子组件变化的回调函数
+     this.childs1.changes.subscribe((changes)=>{
+       console.log(changes);
+
+      })
+  }
+}

ContentChild

获取投影中的dom元素、指令、组件

📝content-parent.html

html
<app-content-child>
+    <div class="head" #head>head</div>
+    <div class="main">main</div>
+    <div class="footer">footer</div>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+</app-content-child>
<app-content-child>
+    <div class="head" #head>head</div>
+    <div class="main">main</div>
+    <div class="footer">footer</div>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+</app-content-child>

📝content-child.html

html
<p>content-child works!</p>
+<ng-content></ng-content>
<p>content-child works!</p>
+<ng-content></ng-content>

📝content-child.ts

typescript
import { AfterViewInit, Component, ContentChild, ElementRef, OnInit } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+  @ContentChild('head',{static:true}) private head:ElementRef //获取投影中的dom元素
+  @ContentChild(ContentBoxComponent) private contentbox:ElementRef //获取组件
+  @ContentChild('cbox',{static:true}) private cbox:ElementRef // 有多个只会获取第一个
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.head);
+   console.log(this.contentbox);
+    console.log(this.cbox);
+
+  }
+}
import { AfterViewInit, Component, ContentChild, ElementRef, OnInit } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+  @ContentChild('head',{static:true}) private head:ElementRef //获取投影中的dom元素
+  @ContentChild(ContentBoxComponent) private contentbox:ElementRef //获取组件
+  @ContentChild('cbox',{static:true}) private cbox:ElementRef // 有多个只会获取第一个
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.head);
+   console.log(this.contentbox);
+    console.log(this.cbox);
+
+  }
+}

ContentChildren

用法类似ViewChildren, 批量获取投影中到组件或指令。

默认只批量获取直属组件,获取所有组件需开启:{ descendants: true }

📝content-parent.html

html
<p>content-parent works!</p>
+<app-content-child>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <div class="container">
+        <app-content-box #cbox></app-content-box>
+        <app-content-box #cbox></app-content-box>
+    </div>
+</app-content-child>
<p>content-parent works!</p>
+<app-content-child>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <div class="container">
+        <app-content-box #cbox></app-content-box>
+        <app-content-box #cbox></app-content-box>
+    </div>
+</app-content-child>

📝content-child.ts

typescript
import { AfterViewInit, Component,ContentChildren,OnInit, QueryList } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+    //ContentChildren没有{static:true}属性
+  @ContentChildren(ContentBoxComponent) private cboxs:QueryList<ContentBoxComponent>
+  @ContentChildren('cbox',{descendants: true}) private cboxss:QueryList<ContentBoxComponent>
+   constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.cboxs);//只获取直属投影组件
+    console.log(this.cboxss);//获取全部投影组件   
+  }
+}
import { AfterViewInit, Component,ContentChildren,OnInit, QueryList } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+    //ContentChildren没有{static:true}属性
+  @ContentChildren(ContentBoxComponent) private cboxs:QueryList<ContentBoxComponent>
+  @ContentChildren('cbox',{descendants: true}) private cboxss:QueryList<ContentBoxComponent>
+   constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.cboxs);//只获取直属投影组件
+    console.log(this.cboxss);//获取全部投影组件   
+  }
+}

自定义管道

typescript
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipepow'
+})
+export class PipepowPipe implements PipeTransform {
+
+  transform(value: number, exponent?: number): number {
+      //value:底数    exponent:指数
+    return Math.pow(value,isNaN(exponent) ? 1: exponent);
+  }
+}
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipepow'
+})
+export class PipepowPipe implements PipeTransform {
+
+  transform(value: number, exponent?: number): number {
+      //value:底数    exponent:指数
+    return Math.pow(value,isNaN(exponent) ? 1: exponent);
+  }
+}

在相应的Module中导入并使用

html
<div> {{8| pipepow}}</div>
+<div> {{8| pipepow:3}}</div>
+<div> {{value | pipepow:2}}</div>
+<div>Boost factor: <input [(ngModel)]="factor"></div>
+<div>Normal power: <input [(ngModel)]="power"></div>
+<div> {{factor | pipepow:power}}</div>
<div> {{8| pipepow}}</div>
+<div> {{8| pipepow:3}}</div>
+<div> {{value | pipepow:2}}</div>
+<div>Boost factor: <input [(ngModel)]="factor"></div>
+<div>Normal power: <input [(ngModel)]="power"></div>
+<div> {{factor | pipepow:power}}</div>

非纯管道

默认的管道都是纯的,Angular 会忽略复合对象中的变化,即管道只会检查原始值或对象引用

WARNING

可如果数组中的元素变化,增删改,由于引用没有变化,不会执行变更检测,所以不会执行管道的逻辑

Pipe2Pipe
typescript
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipe2',
+  pure: false //非纯管道开启方式一
+})
+export class Pipe2Pipe implements PipeTransform {
+
+  transform(allheros: any): any { //赛选会飞的英雄
+    return allheros.filter((item) => item.canFly);
+  }
+
+}
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipe2',
+  pure: false //非纯管道开启方式一
+})
+export class Pipe2Pipe implements PipeTransform {
+
+  transform(allheros: any): any { //赛选会飞的英雄
+    return allheros.filter((item) => item.canFly);
+  }
+
+}
AppComponent
typescript
import { Component } from '@angular/core';
+interface Hero {
+  id: string;
+  name: string;
+  canFly?: boolean;
+}
+
+const HEROES = [
+              {
+                id: 'hero_0',
+                name: '盖伦',
+                canFly: false
+              },
+              {
+                id: 'hero_1',
+                name: '赵信',
+                canFly: false
+              },
+              {
+                id: 'hero_2',
+                name: '嘉文',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '易大师',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '泰达米尔',
+                canFly: true
+              }
+          ];
+@Component({
+  selector: 'app-root',
+  template: `
+     <input type="text" #box (keyup.enter)="addHero(box.value)" placeholder="hero name" />
+     <button (click)="reset()">Reset</button>
+     <div *ngFor="let hero of (heroes | pipe2)">
+       {{hero.name}}
+     </div>
+  `,
+})
+export class AppComponent {
+    heroes: Hero[] = [];
+     canFly = true;
+     constructor() {
+       this.reset();
+     }
+
+     ngOnInit(): void {
+     }
+     addHero(name: string) {
+       name = name.trim();
+       if (name) {
+         // 不改变引用没有用
+         this.heroes.push({ id: 'flier_' + Date.now(), name, canFly: this.canFly });
+        // 开启非纯管道方式二、改变引用,触发变更检测
+        // this.heroes = [...this.heroes,{id:'flier'+Date.now(),name,canFly:this.canFly}]
+       }
+     }
+
+   reset() { this.heroes = HEROES.slice(); }
+}
import { Component } from '@angular/core';
+interface Hero {
+  id: string;
+  name: string;
+  canFly?: boolean;
+}
+
+const HEROES = [
+              {
+                id: 'hero_0',
+                name: '盖伦',
+                canFly: false
+              },
+              {
+                id: 'hero_1',
+                name: '赵信',
+                canFly: false
+              },
+              {
+                id: 'hero_2',
+                name: '嘉文',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '易大师',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '泰达米尔',
+                canFly: true
+              }
+          ];
+@Component({
+  selector: 'app-root',
+  template: `
+     <input type="text" #box (keyup.enter)="addHero(box.value)" placeholder="hero name" />
+     <button (click)="reset()">Reset</button>
+     <div *ngFor="let hero of (heroes | pipe2)">
+       {{hero.name}}
+     </div>
+  `,
+})
+export class AppComponent {
+    heroes: Hero[] = [];
+     canFly = true;
+     constructor() {
+       this.reset();
+     }
+
+     ngOnInit(): void {
+     }
+     addHero(name: string) {
+       name = name.trim();
+       if (name) {
+         // 不改变引用没有用
+         this.heroes.push({ id: 'flier_' + Date.now(), name, canFly: this.canFly });
+        // 开启非纯管道方式二、改变引用,触发变更检测
+        // this.heroes = [...this.heroes,{id:'flier'+Date.now(),name,canFly:this.canFly}]
+       }
+     }
+
+   reset() { this.heroes = HEROES.slice(); }
+}

生命周期

生命周期函数:组件创建、组件更新、组件销毁的时候会触发的一系列的方法。

当 Angular 使用构造函数新建一个组件或指令后,就会按下面的顺序在特定时刻调用这些 生命周期钩子函数。

所有生命周期钩子函数执行顺序
typescript
import { AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, 
+        DoCheck, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit,OnChanges,DoCheck,AfterContentInit,
+        AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy{
+  constructor(){} //组件初始化,写简单的逻辑和数据初始化操作,(获取不到最新输入属性值)
+  ngOnChanges(changes: SimpleChanges): void {
+    console.log('changes ', changes); 
+      //可最早获取到输入属性最新值,输入属性更新时触发,但组件内部改变输入属性是不会触发的
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit '); //适合请求数据初始化组件,只调用一次
+  }
+  ngDoCheck(): void {
+    console.log('ngDoCheck ');
+  }
+
+  ngAfterContentInit(): void {
+      //在组件内容初始化之后调用,只调用一次。
+    console.log('ngAfterContentInit');
+  }
+
+  ngAfterContentChecked(): void {
+      //组件每次检查内容时调用
+    console.log('ngAfterContentChecked ');
+  }
+
+  ngAfterViewInit(): void {
+      //组件相应的视图初始化之后调用,只调用一次。
+    console.log('ngAfterViewInit ');
+  }
+
+  ngAfterViewChecked(): void {
+      //组件每次检查视图时调用
+    console.log('ngAfterViewChecked');
+
+  }
+
+  ngOnDestroy(): void {
+    //指令销毁前调用,适合理一些残存的状态操作:
+    //取消订阅可观察对象和 DOM 事件、停止 interval 计时器、
+    //反注册该指令在全局或应用服务中注册过的所有回调
+    console.log('ngOnDestroy');
+  }
+
+}
import { AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, 
+        DoCheck, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit,OnChanges,DoCheck,AfterContentInit,
+        AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy{
+  constructor(){} //组件初始化,写简单的逻辑和数据初始化操作,(获取不到最新输入属性值)
+  ngOnChanges(changes: SimpleChanges): void {
+    console.log('changes ', changes); 
+      //可最早获取到输入属性最新值,输入属性更新时触发,但组件内部改变输入属性是不会触发的
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit '); //适合请求数据初始化组件,只调用一次
+  }
+  ngDoCheck(): void {
+    console.log('ngDoCheck ');
+  }
+
+  ngAfterContentInit(): void {
+      //在组件内容初始化之后调用,只调用一次。
+    console.log('ngAfterContentInit');
+  }
+
+  ngAfterContentChecked(): void {
+      //组件每次检查内容时调用
+    console.log('ngAfterContentChecked ');
+  }
+
+  ngAfterViewInit(): void {
+      //组件相应的视图初始化之后调用,只调用一次。
+    console.log('ngAfterViewInit ');
+  }
+
+  ngAfterViewChecked(): void {
+      //组件每次检查视图时调用
+    console.log('ngAfterViewChecked');
+
+  }
+
+  ngOnDestroy(): void {
+    //指令销毁前调用,适合理一些残存的状态操作:
+    //取消订阅可观察对象和 DOM 事件、停止 interval 计时器、
+    //反注册该指令在全局或应用服务中注册过的所有回调
+    console.log('ngOnDestroy');
+  }
+
+}

当组件、父组件发生变更检测后都会调用这三个钩子:

模板中的DOM事件触发就会进行变更检测(<input (input)="$event">

ngDoCheck ngAfterContentChecked ngAfterViewChecked

  • 指令与组件共有的钩子
    • ngOnChanges
    • ngOnInit
    • ngDoCheck
    • ngOnDestroy
  • 组件特有的钩子
    • ngAfterContentInit
    • ngAfterContentChecked
    • ngAfterViewInit
    • ngAfterViewChecked

变更检测

默认策略下触发变更检测的时机

typescript
changeDetection:ChangeDetectionStrategy.Default
changeDetection:ChangeDetectionStrategy.Default
  • 事件:页面 click、submit、mouse down……
  • XHR:从后端服务器拿到数据
  • 定时器:setTimeout()、setInterval()

只要某个组件触发了以上中的一个,就会从顶级组件从上至下开始进行变更检测,每个组件都会进行变更检测,

检测组件中的值是否应该改变

注意

已经检测完的组件,不允许在被子组件修改,(子组件不能修改检测完的父组件数据),这就是单向数据流

onPush下触发变更检测时机

typescript
changeDetection:ChangeDetectionStrategy.OnPush
changeDetection:ChangeDetectionStrategy.OnPush

WARNING

onPush策略会把组件从组件树中剥离出去,他和他的子组件都不会检测了;

定时器会触发变更检测,但是依然会跳过onPush策略组件。

TIP

  • 组件的@Input引用发生变化。
  • 组件的 DOM 事件,包括它子组件的 DOM 事件,比如 click、submit、mouse down。
  • Observable 订阅事件,同时设置 Async pipe。
  • 手动调用:ChangeDetectorRef.detectChanges()、ChangeDetectorRef.markForCheck()、ApplicationRef.tick()方法
js
markForCheck() //把该视图显式标记为已更改(脏的),以便它下一轮再次进行检查。
+detectChanges() //检查该视图及其子视图。与 detach 结合使用可以实现局部变更检测。(强行检测)
markForCheck() //把该视图显式标记为已更改(脏的),以便它下一轮再次进行检查。
+detectChanges() //检查该视图及其子视图。与 detach 结合使用可以实现局部变更检测。(强行检测)

动态组件

如果说,之前在模版中调用的组件为静态组件(比如:app-xxx)

那么不用在模版里声明,而是通过ts动态插入到dom中到组件,可以视为动态组件

📝alert.component.ts:

typescript
import {Component, OnInit, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core';
+type AlertTheme = 'primary' | 'danger' | 'warning';
+
+export interface AlertOption {
+  content: string;
+  theme?: AlertTheme;
+}
+
+@Component({
+  selector: 'app-alert',
+  template: `
+    <div [class]="wrapCls" role="alert">
+      <span class="content">{{ options.content }}</span>
+      <i class="close" (click)="closed.emit()">×</i>
+    </div>
+  `,
+  styles: [`
+    .close {
+      display: block;
+      width: 20px;
+      height: 20px;
+      position: absolute;
+      right: 10px;
+      top: 50%;
+      margin-top: -10px;
+      cursor: pointer;
+    }
+  `],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AlertComponent implements OnInit {
+  options: Required<AlertOption> = {
+    content: '',
+    theme: 'primary'
+  }
+
+  @Output() closed = new EventEmitter<void>();
+  constructor() { }
+
+  ngOnInit(): void {}
+
+  get wrapCls(): string {
+    return 'alert alert-' + this.options.theme + ' fixed-top';
+  }
+
+  setOptions(options: AlertOption) {
+    this.options = { ...this.options, ...options };
+  }
+}
import {Component, OnInit, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core';
+type AlertTheme = 'primary' | 'danger' | 'warning';
+
+export interface AlertOption {
+  content: string;
+  theme?: AlertTheme;
+}
+
+@Component({
+  selector: 'app-alert',
+  template: `
+    <div [class]="wrapCls" role="alert">
+      <span class="content">{{ options.content }}</span>
+      <i class="close" (click)="closed.emit()">×</i>
+    </div>
+  `,
+  styles: [`
+    .close {
+      display: block;
+      width: 20px;
+      height: 20px;
+      position: absolute;
+      right: 10px;
+      top: 50%;
+      margin-top: -10px;
+      cursor: pointer;
+    }
+  `],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AlertComponent implements OnInit {
+  options: Required<AlertOption> = {
+    content: '',
+    theme: 'primary'
+  }
+
+  @Output() closed = new EventEmitter<void>();
+  constructor() { }
+
+  ngOnInit(): void {}
+
+  get wrapCls(): string {
+    return 'alert alert-' + this.options.theme + ' fixed-top';
+  }
+
+  setOptions(options: AlertOption) {
+    this.options = { ...this.options, ...options };
+  }
+}

调用 alert.component

typescript
import {ApplicationRef, Component, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector, OnInit} from '@angular/core';
+import {AlertComponent} from '../../components/alert/alert.component';
+
+@Component({
+  selector: 'app-show-data',
+  templateUrl: './show-data.component.html',
+  styleUrls: ['./show-data.component.scss']
+})
+export class ShowDataComponent implements OnInit {
+  private container: AlertComponent;
+  private componentRef: ComponentRef<AlertComponent>;
+  constructor(
+    private cfr: ComponentFactoryResolver,
+    private inject: Injector,
+    private appRef: ApplicationRef
+  ) {}
+
+  ngOnInit(): void {
+
+  }
+
+  showAlert() {
+    if (!this.container) {
+      this.container = this.getContainer();
+    }
+
+    // 调用组件的某个方法执行逻辑,比如下面这个传参
+    this.container.setOptions({ content: '一段提示', theme: 'warning' });
+  }
+
+  private getContainer(): AlertComponent {
+    // 创建指定类型的组件工厂(生产指定类型的组件)
+    const factory = this.cfr.resolveComponentFactory<AlertComponent>(AlertComponent);
+
+    // 根据指定的类型,创建组件的示例
+    this.componentRef = factory.create(this.inject);
+
+    // 将组件试图添加到试图树中,以激活变更检测
+    this.appRef.attachView(this.componentRef.hostView);
+
+    // 将组件到模版(包括app-alert标签),添加到body最后
+    document.body.appendChild((this.componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);
+
+    // 监听组件销毁事件
+    this.componentRef.onDestroy(() => {
+      console.log('componentRef destory');
+    });
+
+    // 获取组件实例,相当于用@ViewChild获取子组件一样
+    const { instance } = this.componentRef;
+
+    // 监听组件到output事件
+    instance.closed.subscribe(() => {
+      this.componentRef.destroy();
+      this.container = null;
+    });
+
+    return instance;
+  }
+}
import {ApplicationRef, Component, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector, OnInit} from '@angular/core';
+import {AlertComponent} from '../../components/alert/alert.component';
+
+@Component({
+  selector: 'app-show-data',
+  templateUrl: './show-data.component.html',
+  styleUrls: ['./show-data.component.scss']
+})
+export class ShowDataComponent implements OnInit {
+  private container: AlertComponent;
+  private componentRef: ComponentRef<AlertComponent>;
+  constructor(
+    private cfr: ComponentFactoryResolver,
+    private inject: Injector,
+    private appRef: ApplicationRef
+  ) {}
+
+  ngOnInit(): void {
+
+  }
+
+  showAlert() {
+    if (!this.container) {
+      this.container = this.getContainer();
+    }
+
+    // 调用组件的某个方法执行逻辑,比如下面这个传参
+    this.container.setOptions({ content: '一段提示', theme: 'warning' });
+  }
+
+  private getContainer(): AlertComponent {
+    // 创建指定类型的组件工厂(生产指定类型的组件)
+    const factory = this.cfr.resolveComponentFactory<AlertComponent>(AlertComponent);
+
+    // 根据指定的类型,创建组件的示例
+    this.componentRef = factory.create(this.inject);
+
+    // 将组件试图添加到试图树中,以激活变更检测
+    this.appRef.attachView(this.componentRef.hostView);
+
+    // 将组件到模版(包括app-alert标签),添加到body最后
+    document.body.appendChild((this.componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);
+
+    // 监听组件销毁事件
+    this.componentRef.onDestroy(() => {
+      console.log('componentRef destory');
+    });
+
+    // 获取组件实例,相当于用@ViewChild获取子组件一样
+    const { instance } = this.componentRef;
+
+    // 监听组件到output事件
+    instance.closed.subscribe(() => {
+      this.componentRef.destroy();
+      this.container = null;
+    });
+
+    return instance;
+  }
+}

v9和v10,动态组件都不需要entryComponents了,当然写了也没有问题 从v11开始,entryComponents可能被删除 v8及以前,动态组件一定要声明entryComponents

NgTemplateOutlet指令

NgTemplateOutlet是一个结构型指令

📝app.component.html

html
<app-tmp-outlet [render]="mycontent"></app-tmp-outlet>
+<ng-template #mycontent>
+    <div>一段父组件传入的内容</div>
+</ng-template>
+
+<!--使用tem-outlet组件中的数据-->
+<ng-template #mycontent let-context let-val="value">
+    <div>一段父组件传入的内容</div>
+    <div>使用outlet中的context:{{context}}</div>
+    <div>使用outlet中的value:{{val}}</div>
+</ng-template>
<app-tmp-outlet [render]="mycontent"></app-tmp-outlet>
+<ng-template #mycontent>
+    <div>一段父组件传入的内容</div>
+</ng-template>
+
+<!--使用tem-outlet组件中的数据-->
+<ng-template #mycontent let-context let-val="value">
+    <div>一段父组件传入的内容</div>
+    <div>使用outlet中的context:{{context}}</div>
+    <div>使用outlet中的value:{{val}}</div>
+</ng-template>

📝tmp-outlet.component.html

html
<p>tmp-outlet works!</p>
+<ng-container [ngTemplateOutlet]="render || default"></ng-container>
+
+<!--传递出去tem-outlet组件中的数据-->
+<ng-container [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-container>
+<!-- <ng-container *ngTemplateOutlet="render || default ;context:myContext"></ng-container>简写 -->
+
+<!--ng-template使用效果一样 -->
+<ng-template [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-template>
+<ng-template *ngTemplateOutlet="render || default ;context:myContext"></ng-template>
+<ng-template #default>
+    <div>一段组价默认的内容</div>
+</ng-template>
+
+<!-- context在内部ng-template也可以绑定 -->
+<ng-template #default let-context let-val="value">
+    <div>一段组价默认的内容</div>
+    <div> context:{{context}}</div>
+    <div> value:{{val}}</div>
+</ng-template>
<p>tmp-outlet works!</p>
+<ng-container [ngTemplateOutlet]="render || default"></ng-container>
+
+<!--传递出去tem-outlet组件中的数据-->
+<ng-container [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-container>
+<!-- <ng-container *ngTemplateOutlet="render || default ;context:myContext"></ng-container>简写 -->
+
+<!--ng-template使用效果一样 -->
+<ng-template [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-template>
+<ng-template *ngTemplateOutlet="render || default ;context:myContext"></ng-template>
+<ng-template #default>
+    <div>一段组价默认的内容</div>
+</ng-template>
+
+<!-- context在内部ng-template也可以绑定 -->
+<ng-template #default let-context let-val="value">
+    <div>一段组价默认的内容</div>
+    <div> context:{{context}}</div>
+    <div> value:{{val}}</div>
+</ng-template>

📝tmp-outlet.component.ts

typescript
import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-tmp-outlet',
+  templateUrl: './tmp-outlet.component.html',
+  styleUrls: ['./tmp-outlet.component.css']
+})
+export class TmpOutletComponent implements OnInit {
+
+  @Input()  render 
+  myContext = {$implicit: 'tmp-outlet组件里的context', value: 'tmp-outlet组件里的value'};
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-tmp-outlet',
+  templateUrl: './tmp-outlet.component.html',
+  styleUrls: ['./tmp-outlet.component.css']
+})
+export class TmpOutletComponent implements OnInit {
+
+  @Input()  render 
+  myContext = {$implicit: 'tmp-outlet组件里的context', value: 'tmp-outlet组件里的value'};
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
+ + + + \ No newline at end of file diff --git "a/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.html" "b/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.html" new file mode 100644 index 00000000..f4fb78cc --- /dev/null +++ "b/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.html" @@ -0,0 +1,783 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

双向绑定

1. 基本双向绑定

方法一:

📝父组件:

typescript
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: `
+<app-sbind [size]="fontSizePx" (change)=" fontSizePx = $event"></app-sbind>
+
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>
+`,
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: `
+<app-sbind [size]="fontSizePx" (change)=" fontSizePx = $event"></app-sbind>
+
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>
+`,
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}

📝子组件:

typescript
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  template: `<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size">sbind 字体大小: {{size}}px</p>
+</div>`,
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  @Output() change = new EventEmitter<number>();
+    
+  dec() {
+    this.change.emit(this.size-1)
+  }
+  inc() {
+    this.change.emit(this.size+1)
+  }
+    
+  constructor() { }
+  ngOnInit(): void {
+  }
+}
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  template: `<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size">sbind 字体大小: {{size}}px</p>
+</div>`,
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  @Output() change = new EventEmitter<number>();
+    
+  dec() {
+    this.change.emit(this.size-1)
+  }
+  inc() {
+    this.change.emit(this.size+1)
+  }
+    
+  constructor() { }
+  ngOnInit(): void {
+  }
+}

方法二:(联合写法)

📝父组件:app.component.html

html
<app-sbind [(size)]="fontSizePx"></app-sbind>
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>
<app-sbind [(size)]="fontSizePx"></app-sbind>
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>

📝父组件:app.component.ts

typescript
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}

📝子组件:sbind.component.html

html
<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size"> sbind 字体大小: {{size}}px</p>
+</div>
<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size"> sbind 字体大小: {{size}}px</p>
+</div>

📝子组件:sbind.component.ts

typescript
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  templateUrl: './sbind.component.html',
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  // 双向绑定语法:output变量名=输入属性名+Change
+  @Output() sizeChange = new EventEmitter<number>();
+  constructor() { }
+
+  dec() {//减
+    this.sizeChange.emit(this.size-1)
+  }
+  inc() {//加
+    this.sizeChange.emit(this.size+1)
+  }
+  ngOnInit(): void {
+  }
+}
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  templateUrl: './sbind.component.html',
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  // 双向绑定语法:output变量名=输入属性名+Change
+  @Output() sizeChange = new EventEmitter<number>();
+  constructor() { }
+
+  dec() {//减
+    this.sizeChange.emit(this.size-1)
+  }
+  inc() {//加
+    this.sizeChange.emit(this.size+1)
+  }
+  ngOnInit(): void {
+  }
+}

2. input双向绑定

普通写法:

typescript
<input type ="text" [value]="inputVal" (input)="inputVal = $event.target.value">
+<p>{{inputVal}}</p> //默认值 inputVal=''
<input type ="text" [value]="inputVal" (input)="inputVal = $event.target.value">
+<p>{{inputVal}}</p> //默认值 inputVal=''

简写形式:

WARNING

ngMoel 指令来源于FormsModule模块

[(ngMoel)]可拆解为:

  1. 名为ngModel的输入属性

  2. 名为ngModelChange的输出属性

html
<input type ="text" [(ngMoel)] ="inputVal">
+<p>{{inputVal}}</p> //默认值 inputVal=''
+<!-- <input type="text" [ngModel] = "inputVal" (ngModelChange) ="inputVal= $event">
+<p>{{inputVal}}</p> 完整写法-->
<input type ="text" [(ngMoel)] ="inputVal">
+<p>{{inputVal}}</p> //默认值 inputVal=''
+<!-- <input type="text" [ngModel] = "inputVal" (ngModelChange) ="inputVal= $event">
+<p>{{inputVal}}</p> 完整写法-->

3. 表单Form中双向绑定

TIP

表单中使用[(ngModel)],满足下列两个条件之一:

  • 给控件加上name属性
  • 将ngModelOptions.standalone设为true
html
 <form>
+    <input [(ngModel)]="value" name="name" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ name: 'name' }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ standalone: true }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{  name: 'name' ,standalone: true }" />
+  </form>
 <form>
+    <input [(ngModel)]="value" name="name" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ name: 'name' }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ standalone: true }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{  name: 'name' ,standalone: true }" />
+  </form>
ngModel拓展
typescript
@ViewChild(NgModel) private ngModel : NgModel;
+getVal(){
+    console.log(this.ngModel.viewModel)//获取[(ngModel)]所绑定input的值
+}
+setVal(){
+    this.ngModel.viewToModelUpdate( 'newValue')//赋值(不太好使)
+}
@ViewChild(NgModel) private ngModel : NgModel;
+getVal(){
+    console.log(this.ngModel.viewModel)//获取[(ngModel)]所绑定input的值
+}
+setVal(){
+    this.ngModel.viewToModelUpdate( 'newValue')//赋值(不太好使)
+}

属性型指令

指令:用于改变DOM元素的外观或行为的指令(组件是一种特殊的指令)

组件改为属性型指令

📝AppComponent

html
<div app-for>dasfsada</div>
<div app-for>dasfsada</div>
typescript
import {Component} from '@angular/core';
+@Component({
+  selector: '[app-decr]',//属性选择器
+  template: `   
+  `,
+})
+export class DecrComponent {
+  constructor() {}
+}
import {Component} from '@angular/core';
+@Component({
+  selector: '[app-decr]',//属性选择器
+  template: `   
+  `,
+})
+export class DecrComponent {
+  constructor() {}
+}

结构型指令

*ngIf指令

html
 <p *ngIf="isShow">一段文字 {{ isShow }}</p> 
+<!-- <p *ngIf="isShow as s">一段文字 {{ s }}</p> 局部变量:只能在标签内部使用-->
+isShow:true显示,反之(取决于绑定的值是否为真)
 <p *ngIf="isShow">一段文字 {{ isShow }}</p> 
+<!-- <p *ngIf="isShow as s">一段文字 {{ s }}</p> 局部变量:只能在标签内部使用-->
+isShow:true显示,反之(取决于绑定的值是否为真)

WARNING

会改变DOM结构,原理:移除和插入DOM节点

*ngIf 完整写法
html
 <ng-template [ngIf]="isShow" let-s>
+     <p *ngIf="isShow">一段文字 {{ isShow }} {{s}}</p> 
+ </ng-template>
 <ng-template [ngIf]="isShow" let-s>
+     <p *ngIf="isShow">一段文字 {{ isShow }} {{s}}</p> 
+ </ng-template>

ngIfElese

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: `
+    <div *ngIf="condition; else elseBlock">condition为真时显示</div>
+
+    <ng-template ##elseBlock> 
+      <p> condition为假时显示 </p>
+    </ng-template>
+  `,
+}) // ##elseBlock:模板的引用
+export class IfComp {
+  condition = true;
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: `
+    <div *ngIf="condition; else elseBlock">condition为真时显示</div>
+
+    <ng-template ##elseBlock> 
+      <p> condition为假时显示 </p>
+    </ng-template>
+  `,
+}) // ##elseBlock:模板的引用
+export class IfComp {
+  condition = true;
+}

ngIfThen

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: `
+    <div *ngIf="condition; then thenBlock else elseBlock"></div>
+    <ng-template ##thenBlock> condition为true时显示</ng-template>
+    <ng-template ##elseBlock> condition为false时显示</ng-template>
+  `,
+})//只会显示一个ng-template,第一个div只是用于承载,并不会显示
+export class IfComp {
+  condition = true;
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: `
+    <div *ngIf="condition; then thenBlock else elseBlock"></div>
+    <ng-template ##thenBlock> condition为true时显示</ng-template>
+    <ng-template ##elseBlock> condition为false时显示</ng-template>
+  `,
+})//只会显示一个ng-template,第一个div只是用于承载,并不会显示
+export class IfComp {
+  condition = true;
+}
TemplateRef拓展
typescript
import {Component, OnInit, ChangeDetectionStrategy, ViewChild, TemplateRef, AfterViewInit} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: `
+    <button(click)="condition = !condition">toggle block</button>
+    <p *ngIf="condition else elseBlocks">{{ condition }} === true 时显示</p>
+    
+	<ng-template ##firstTpl>
+      <p>{{ condition }} === false 时显示</p>
+    </ng-template>
+  `,
+})
+export class IfComponent implements OnInit, AfterViewInit {
+  elseBlocks: TemplateRef<any> = null; //获取组件的变量elseBlocks
+  @ViewChild('firstTpl', {static: true}) primaryBlock: TemplateRef<any> = null;
+  condition = false;
+  constructor() {
+
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit', this.primaryBlock);
+    this.elseBlocks = this.primaryBlock;
+   //获取到##firstTpl模板引用赋值给elseBlocks变量
+  }
+}
+//运行效果和ngIfElese案例一样
import {Component, OnInit, ChangeDetectionStrategy, ViewChild, TemplateRef, AfterViewInit} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: `
+    <button(click)="condition = !condition">toggle block</button>
+    <p *ngIf="condition else elseBlocks">{{ condition }} === true 时显示</p>
+    
+	<ng-template ##firstTpl>
+      <p>{{ condition }} === false 时显示</p>
+    </ng-template>
+  `,
+})
+export class IfComponent implements OnInit, AfterViewInit {
+  elseBlocks: TemplateRef<any> = null; //获取组件的变量elseBlocks
+  @ViewChild('firstTpl', {static: true}) primaryBlock: TemplateRef<any> = null;
+  condition = false;
+  constructor() {
+
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit', this.primaryBlock);
+    this.elseBlocks = this.primaryBlock;
+   //获取到##firstTpl模板引用赋值给elseBlocks变量
+  }
+}
+//运行效果和ngIfElese案例一样

*ngFor指令

typescript
import {Component} from '@angular/core';
+
+@Component({
+  selector: 'app-for',
+  template: `
+    <ul>
+      <li *ngFor="let item of Persons; 
+			index as i; count as len; let ev = even; let od = odd; let f = first; let l = last;
+			trackBy: trackByPerson">{{ item.name }}</li>
+    </ul>
+  `,
+})
+export class ForComponent {
+     Persons = [
+  {
+    id: 'p1',
+    name: '张三'
+  },
+    {
+    id: 'p2',
+    name: '李四'
+  },
+    {
+    id: 'p3',
+    name: '王五'
+  },
+  
+];
+trackByPerson(index,item){
+    return item.id	//追踪id,id值不变不刷新(提升性能)
+  }
+}
import {Component} from '@angular/core';
+
+@Component({
+  selector: 'app-for',
+  template: `
+    <ul>
+      <li *ngFor="let item of Persons; 
+			index as i; count as len; let ev = even; let od = odd; let f = first; let l = last;
+			trackBy: trackByPerson">{{ item.name }}</li>
+    </ul>
+  `,
+})
+export class ForComponent {
+     Persons = [
+  {
+    id: 'p1',
+    name: '张三'
+  },
+    {
+    id: 'p2',
+    name: '李四'
+  },
+    {
+    id: 'p3',
+    name: '王五'
+  },
+  
+];
+trackByPerson(index,item){
+    return item.id	//追踪id,id值不变不刷新(提升性能)
+  }
+}
ngFor局部变量
js
 index: number	//可迭代对象中当前条目的索引。
+ count: number	//可迭代对象的长度。
+ first: boolean	//如果当前条目是可迭代对象中的第一个条目则为 true。
+ last: boolean	//如果当前条目是可迭代对象中的最后一个条目则为 true。
+ even: boolean	//如果当前条目在可迭代对象中的索引号为偶数则为 true。
+ odd: boolean	//如果当前条目在可迭代对象中的索引号为奇数则为 true。
+ $implicit: T	//迭代目标(绑定到ngForOf)中每个条目的值。
+ ngForOf: NgIterable<T>	//迭代表达式的值。当表达式不局限于访问某个属性时,这会非常有用,比如在使用 async 管道时(userStreams | async)。
 index: number	//可迭代对象中当前条目的索引。
+ count: number	//可迭代对象的长度。
+ first: boolean	//如果当前条目是可迭代对象中的第一个条目则为 true。
+ last: boolean	//如果当前条目是可迭代对象中的最后一个条目则为 true。
+ even: boolean	//如果当前条目在可迭代对象中的索引号为偶数则为 true。
+ odd: boolean	//如果当前条目在可迭代对象中的索引号为奇数则为 true。
+ $implicit: T	//迭代目标(绑定到ngForOf)中每个条目的值。
+ ngForOf: NgIterable<T>	//迭代表达式的值。当表达式不局限于访问某个属性时,这会非常有用,比如在使用 async 管道时(userStreams | async)。
*ngFor展开写法
html
 <ul>
+     <ng-template
+       ngFor
+       [ngForOf]="heros"
+       [ngForTrackBy]="trackByHero"
+       let-item
+       let-i="index"
+       let-od="odd"
+       let-ev="even"
+       let-len="count"
+       let-f="first"
+       let-l="last">
+       <li [class.even]="ev" [class.odd]="od">
+         <p>index: {{ i }}</p>
+         <p>count: {{ len }}</p>
+         <p>name: {{ item.name }}</p>
+         <p>first: {{ f }} -- last: {{ l }}</p>
+         <hr>
+       </li>
+     </ng-template>
+   </ul>
 <ul>
+     <ng-template
+       ngFor
+       [ngForOf]="heros"
+       [ngForTrackBy]="trackByHero"
+       let-item
+       let-i="index"
+       let-od="odd"
+       let-ev="even"
+       let-len="count"
+       let-f="first"
+       let-l="last">
+       <li [class.even]="ev" [class.odd]="od">
+         <p>index: {{ i }}</p>
+         <p>count: {{ len }}</p>
+         <p>name: {{ item.name }}</p>
+         <p>first: {{ f }} -- last: {{ l }}</p>
+         <hr>
+       </li>
+     </ng-template>
+   </ul>

[ngSwitch]指令

WARNING

[ngSwitch] 为属性型指令

*ngSwitchCase为结构型指令

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-switch',
+  template: `
+    <p>
+      <input type="radio" name="fruit" value="apple" id="apple" [(ngModel)]="fruit" />
+      <label for="apple">🍎</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="pear" id="pear" [(ngModel)]="fruit" />
+      <label for="pear">🍐</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="grape" id="grape" [(ngModel)]="fruit" />
+      <label for="grape">🍇</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="other" id="other" [(ngModel)]="fruit" />
+      <label for="other">other</label>
+    </p>
+    
+    selected fruit: {{ fruit }}
+    
+    <div class="content" [ngSwitch]="fruit">
+      <p *ngSwitchCase="'apple'">这是 苹果</p>
+      <p *ngSwitchCase="'pear'"> 这是 梨</p>
+      <p *ngSwitchCase="'grape'">这是 葡萄</p>
+      <p *ngSwitchDefault>啥都不是</p>
+    </div>
+  `,
+})
+export class SwitchComponent {
+  fruit = '';
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-switch',
+  template: `
+    <p>
+      <input type="radio" name="fruit" value="apple" id="apple" [(ngModel)]="fruit" />
+      <label for="apple">🍎</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="pear" id="pear" [(ngModel)]="fruit" />
+      <label for="pear">🍐</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="grape" id="grape" [(ngModel)]="fruit" />
+      <label for="grape">🍇</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="other" id="other" [(ngModel)]="fruit" />
+      <label for="other">other</label>
+    </p>
+    
+    selected fruit: {{ fruit }}
+    
+    <div class="content" [ngSwitch]="fruit">
+      <p *ngSwitchCase="'apple'">这是 苹果</p>
+      <p *ngSwitchCase="'pear'"> 这是 梨</p>
+      <p *ngSwitchCase="'grape'">这是 葡萄</p>
+      <p *ngSwitchDefault>啥都不是</p>
+    </div>
+  `,
+})
+export class SwitchComponent {
+  fruit = '';
+}
[ngSwitch]展开写法
typescript
 <div class="content" [ngSwitch]="fruit">
+       <ng-template ngSwitchCase="apple">
+         <p>这是苹果</p>
+       </ng-template>
+       <ng-template ngSwitchCase="pear">
+         <p>这是梨</p>
+       </ng-template>
+       <ng-template ngSwitchCase="grape">
+         <p>这是葡萄</p>
+       </ng-template>
+       <ng-template ngSwitchDefault>
+         <p>啥都不是</p>
+       </ng-template>
+     </div>
 <div class="content" [ngSwitch]="fruit">
+       <ng-template ngSwitchCase="apple">
+         <p>这是苹果</p>
+       </ng-template>
+       <ng-template ngSwitchCase="pear">
+         <p>这是梨</p>
+       </ng-template>
+       <ng-template ngSwitchCase="grape">
+         <p>这是葡萄</p>
+       </ng-template>
+       <ng-template ngSwitchDefault>
+         <p>啥都不是</p>
+       </ng-template>
+     </div>

自定义指令

使用:

html
<p appHighlight highlightColor ='red'></p>
+<p appHighlight [highlightColor] ='color'></p>
+<p appHighlight='color'></p> <!-- 起别名后,输入属性和指令名设为一样-->
<p appHighlight highlightColor ='red'></p>
+<p appHighlight [highlightColor] ='color'></p>
+<p appHighlight='color'></p> <!-- 起别名后,输入属性和指令名设为一样-->

自定义高亮指令(属性型)

typescript
import {Directive, ElementRef, EventEmitter, HostListener, Input, Output} from '@angular/core';
+
+@Directive({
+  selector: '[appHighlight]'
+})
+export class HighlightDirective {
+  @Input() highlightColor: string;
+ // @Input('appHighlight') highlightColor: string;起别名
+  @Output() colorChange = new EventEmitter<string>();
+    //1.获取dom
+  constructor(private el: ElementRef) {
+    console.log('appHighlight');
+  }
+   
+  @HostListener('mouseenter') onMouseEnter() {
+    this.highlight(this.highlightColor || 'yellow');
+  }
+	//内部事件监听
+  @HostListener('mouseleave',['$event']) onMouseLeave() {
+    this.highlight('');
+      console.log(event)	//传递事件对象
+  }
+
+  private highlight(color: string) {
+      //2.操作dom (操作dom备用选择)
+    this.el.nativeElement.style.backgroundColor = color;
+    this.colorChange.emit(color);
+  }
+}
import {Directive, ElementRef, EventEmitter, HostListener, Input, Output} from '@angular/core';
+
+@Directive({
+  selector: '[appHighlight]'
+})
+export class HighlightDirective {
+  @Input() highlightColor: string;
+ // @Input('appHighlight') highlightColor: string;起别名
+  @Output() colorChange = new EventEmitter<string>();
+    //1.获取dom
+  constructor(private el: ElementRef) {
+    console.log('appHighlight');
+  }
+   
+  @HostListener('mouseenter') onMouseEnter() {
+    this.highlight(this.highlightColor || 'yellow');
+  }
+	//内部事件监听
+  @HostListener('mouseleave',['$event']) onMouseLeave() {
+    this.highlight('');
+      console.log(event)	//传递事件对象
+  }
+
+  private highlight(color: string) {
+      //2.操作dom (操作dom备用选择)
+    this.el.nativeElement.style.backgroundColor = color;
+    this.colorChange.emit(color);
+  }
+}

相对于原生事件监听 addEventListener()  的优点 :

  1. 会自动销毁,不会导致内存泄漏

  2. 不用必须确保每个DOM API都能用

自定义unless指令(结构型)

定义
typescript
import {Directive, Input, OnChanges, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
+export class UnlessContext<T = unknown> {
+  $implicit: T = null;
+  appUnless: T = null;
+  attr: T = null;
+}
+@Directive({
+  selector: '[appUnless]'
+})
+export class UnlessDirective implements OnChanges {
+  @Input('appUnless') unless: boolean;
+  private hasView = false;//是否已显示
+  private context = new UnlessContext();
+  
+  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {
+    // console.log(this.templateRef);
+    // console.log(this.viewContainer);
+  }
+	//监听输入属性变化
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes['unless']) {
+    this.context.$implicit = this.context.appUnless = this.unless;
+    this.context.attr = 'aaab';
+      if (this.unless) {
+        if (this.hasView) {
+          this.viewContainer.clear();
+          this.hasView = false;
+        }
+      } else {
+        if (!this.hasView) {
+          // 这里使用的构造提供的模版(this.templateRef)
+          // 实战中可以通过一个input属性传入模版
+          this.viewContainer.createEmbeddedView(this.templateRef, this.context);
+          this.hasView = true;
+        }
+      }
+    }
+  }
+}
import {Directive, Input, OnChanges, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
+export class UnlessContext<T = unknown> {
+  $implicit: T = null;
+  appUnless: T = null;
+  attr: T = null;
+}
+@Directive({
+  selector: '[appUnless]'
+})
+export class UnlessDirective implements OnChanges {
+  @Input('appUnless') unless: boolean;
+  private hasView = false;//是否已显示
+  private context = new UnlessContext();
+  
+  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {
+    // console.log(this.templateRef);
+    // console.log(this.viewContainer);
+  }
+	//监听输入属性变化
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes['unless']) {
+    this.context.$implicit = this.context.appUnless = this.unless;
+    this.context.attr = 'aaab';
+      if (this.unless) {
+        if (this.hasView) {
+          this.viewContainer.clear();
+          this.hasView = false;
+        }
+      } else {
+        if (!this.hasView) {
+          // 这里使用的构造提供的模版(this.templateRef)
+          // 实战中可以通过一个input属性传入模版
+          this.viewContainer.createEmbeddedView(this.templateRef, this.context);
+          this.hasView = true;
+        }
+      }
+    }
+  }
+}
调用
typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+     <section>
+       <h3>unless</h3>
+       <button  (click)="showUnless = !showUnless">toggle unless {{ showUnless }}</button>
+       <p *appUnless="showUnless">测试unless driective -- {{ showUnless }}</p>
+       <p *appUnless="showUnless as un">测试unless driective alias un -- {{ un }}</p>
+       <p *appUnless="showUnless; let un; let attr=attr;">别名:  {{ un }} attr: {{ attr }}</p>
+     </section>
+  `,
+})
+export class AppComponent {
+  show = false;	//false: 显示 	true: 隐藏
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+     <section>
+       <h3>unless</h3>
+       <button  (click)="showUnless = !showUnless">toggle unless {{ showUnless }}</button>
+       <p *appUnless="showUnless">测试unless driective -- {{ showUnless }}</p>
+       <p *appUnless="showUnless as un">测试unless driective alias un -- {{ un }}</p>
+       <p *appUnless="showUnless; let un; let attr=attr;">别名:  {{ un }} attr: {{ attr }}</p>
+     </section>
+  `,
+})
+export class AppComponent {
+  show = false;	//false: 显示 	true: 隐藏
+}

模板元素

ng-template

html
<ng-template>是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。
+事实上,在渲染视图之前,Angular 会把 <ng-template> 及其内容替换为一个注释。
<ng-template>是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。
+事实上,在渲染视图之前,Angular 会把 <ng-template> 及其内容替换为一个注释。

WARNING

没有使用结构型指令,ng-template中的元素是不可见的

ng-container

html
Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。
+<ng-container> 是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScript 中 if 块中的花括号。
Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。
+<ng-container> 是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScript 中 if 块中的花括号。
js
if (someCondition) {
+  statement1;
+  statement2;
+  statement3;
+}
if (someCondition) {
+  statement1;
+  statement2;
+  statement3;
+}

模板引用变量

使用井号(##)声明模板引用变量,可以获取DOM 元素、指令、组件、TemplateRef 或 Web Component。

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-tpl-var',
+  template: `
+    <input ##phone placeholder="phone number" />
+ 	<input ref-phone placeholder="phone number" />
+    <button (click)="callPhone(phone.value)">Call</button>
+  `,
+})	//两种写法
+export class TplVarComponent {
+  constructor() { }
+  callPhone(value: string) {
+    console.log('callPhone', value);
+  }
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-tpl-var',
+  template: `
+    <input ##phone placeholder="phone number" />
+ 	<input ref-phone placeholder="phone number" />
+    <button (click)="callPhone(phone.value)">Call</button>
+  `,
+})	//两种写法
+export class TplVarComponent {
+  constructor() { }
+  callPhone(value: string) {
+    console.log('callPhone', value);
+  }
+}

在外部获取组件引用,绑定组件内方法

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+    
+      <button (click)="sizer.inc()">app inc</button>
+      <app-sbind [(size)]="size" ##sizer></app-sbind>
+      size: {{ size }}
+    
+  `,
+})
+export class AppComponent {
+  size = 16;
+  constructor() { }
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: `
+    
+      <button (click)="sizer.inc()">app inc</button>
+      <app-sbind [(size)]="size" ##sizer></app-sbind>
+      size: {{ size }}
+    
+  `,
+})
+export class AppComponent {
+  size = 16;
+  constructor() { }
+}

操作符

管道 |

WARNING

模板变量可以通过一条或多条管道格式化数据,

默认的管道都是纯的,Angular 会忽略复合对象中的变化,即管道只会检查原始值或对象引用,

如果数组中的元素变化,增删改,引用没有变化,而不会执行管道的逻辑。

管道名称作用
DatePipe格式化日期
DecimalPipe数字转字符串,并可以指定格式
KeyValuePipe使ngFor可以循环Object或Map对象
JsonPipe将值转成json格式
TitleCasePipe把首字母大写,其它小写
SlicePipe截取Array或String
PercentPipe数字转百分比
LowerCasePipe转化为小写
UpperCasePipe转化为大写
AsyncPipe自动订阅模板中的Observable或Promise

安全链?

用于可能为空的引用需要使用时,对null、undefined进行保护,保证数据请求前能正常渲染模板

html
<p>{{person?.name}}</p>
<p>{{person?.name}}</p>

非空断言!

DANGER

在ts中,开启--strictNullChecks后,将一个可能是undefined或null的变量赋给一个有确切类型的变量时,会报错。在特定情况下,我们断定变量一定不是undefined或null,就可以使用非空断言操作符。

使用非空断言的两个步骤:

tsconfig.json中设置"strictNullChecks": true

tslint.json中设置 "no-non-null-assertion": false

类型转换函数$any()

绑定的表达式不能或很难指定类型时使用

假设无法确定item的类型,也就不能确定item是否有bestByDate,这时就会报错。

可以用$any()把item视为any类型,避免其报错(也可以用这个函数绑定组件中不存在的变量)

typescript
<p> {{$any(item).bestByDate}}</p>
<p> {{$any(item).bestByDate}}</p>
+ + + + \ No newline at end of file diff --git "a/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" "b/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" new file mode 100644 index 00000000..17f1316c --- /dev/null +++ "b/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.html" @@ -0,0 +1,466 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、前置知识

虚拟DOM

jsx
const VDOM = (  /* 此处一定不要写引号,因为不是字符串 */
+			<h1 id="title">
+				<span>Hello,React</span>
+			</h1>
+		)
+//2.渲染虚拟DOM到页面   准备好一个“容器”<div id="root"></div> 
+ReactDOM.render(VDOM,document.getElementById('root'))
const VDOM = (  /* 此处一定不要写引号,因为不是字符串 */
+			<h1 id="title">
+				<span>Hello,React</span>
+			</h1>
+		)
+//2.渲染虚拟DOM到页面   准备好一个“容器”<div id="root"></div> 
+ReactDOM.render(VDOM,document.getElementById('root'))

关于虚拟DOM:

1.本质是Object类型的对象(一般对象)

​ 2.虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。

​ 3.虚拟DOM最终会被React转化为真实DOM,呈现在页面上

JSX语法规则

​ 1.定义虚拟DOM时,不要写引号。

​ 2.标签中混入JS表达式时要用 {}

​ 3.样式的类名指定不要用class,要用className。

​ 4.只有一个根标签

​ 5.标签必须闭合

​ 6.标签首字母

注意

一定注意区分:【js语句(代码)】与【js表达式】

1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方

 (1). a
+      (2). a+b
+      (3). demo(1)
+      (4). arr.map() 
+      (5). function test () {}
+

2.语句(代码):

js
(1).if(){}
+(2).for(){}
+(3).switch(){case:xxxx}
(1).if(){}
+(2).for(){}
+(3).switch(){case:xxxx}

二、组件

函数式组件

js
	<!-- 准备好一个容器-->
+	<div id="root"></div>
+	
+	<!-- 引入react核心库 -->
+	<script type="text/javascript" src="../js/react.development.js"></script>
+	<!-- 引入react-dom用于支持react操作DOM -->
+	<script type="text/javascript" src="../js/react-dom.development.js"></script>
+	<!-- 引入babel用于将jsx转为js -->
+	<script type="text/javascript" src="../js/babel.min.js"></script>
+
+	<script type="text/babel">
+		//1.创建函数式组件
+		function MyComponent(){
+			console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
+			return <h2>函数式组件</h2>
+		}
+		//2.渲染组件到页面
+		ReactDOM.render(<MyComponent/>,document.getElementById('root'))
+		/* 
+			执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
+					1.React解析组件标签,找到了MyComponent组件。
+					2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
+		*/
+	</script>
	<!-- 准备好一个容器-->
+	<div id="root"></div>
+	
+	<!-- 引入react核心库 -->
+	<script type="text/javascript" src="../js/react.development.js"></script>
+	<!-- 引入react-dom用于支持react操作DOM -->
+	<script type="text/javascript" src="../js/react-dom.development.js"></script>
+	<!-- 引入babel用于将jsx转为js -->
+	<script type="text/javascript" src="../js/babel.min.js"></script>
+
+	<script type="text/babel">
+		//1.创建函数式组件
+		function MyComponent(){
+			console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
+			return <h2>函数式组件</h2>
+		}
+		//2.渲染组件到页面
+		ReactDOM.render(<MyComponent/>,document.getElementById('root'))
+		/* 
+			执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
+					1.React解析组件标签,找到了MyComponent组件。
+					2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
+		*/
+	</script>

类式组件

js
//创建类式组件
+class MyComponent extends React.Component {
+	render(){
+		//render在MyComponent的原型对象上,供实例使用。
+		//render中的this指向MyComponent组件实例对象。
+		console.log('render中的this:',this);
+		return <h2>类式组件</h2>
+	}
+}
+//渲染组件到页面
+ReactDOM.render(<MyComponent/>,document.getElementById('root'))
//创建类式组件
+class MyComponent extends React.Component {
+	render(){
+		//render在MyComponent的原型对象上,供实例使用。
+		//render中的this指向MyComponent组件实例对象。
+		console.log('render中的this:',this);
+		return <h2>类式组件</h2>
+	}
+}
+//渲染组件到页面
+ReactDOM.render(<MyComponent/>,document.getElementById('root'))

TIP

执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?

​ 1.React解析组件标签,找到了MyComponent组件。

​ 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。

​ 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。

补充

受控组件:React 中受控组件的是指表单元素的控制是交给 React ,表单元素的值是完全交由组件的 state 控制。

​ 受控组件也可以用于描述内部状态由传入 props 控制的 React 自定义组件。

非受控组件: 表单元素的状态并不受 React 组件状态的影响,表单元素的值存储于 DOM 元素中。

​ 如果要 React 组件要获取 DOM 元素的值,需要通过绑定 ref 的方式去获取。

组实例三大属性

state

jsx
//1.创建组件
+class Weather extends React.Component{
+	//初始化状态
+	state = {isHot:false,wind:'微风'}
+	render(){
+		const {isHot,wind} = this.state
+		return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}{wind}</h1>
+	}
+	//自定义方法————要用赋值语句的形式+箭头函数 **
+	changeWeather = () =>{
+		const isHot = this.state.isHot
+		this.setState({isHot:!isHot})
+	}
+}
+//2.渲染组件到页面
+ReactDOM.render(<Weather/>,document.getElementById('test'))
//1.创建组件
+class Weather extends React.Component{
+	//初始化状态
+	state = {isHot:false,wind:'微风'}
+	render(){
+		const {isHot,wind} = this.state
+		return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}{wind}</h1>
+	}
+	//自定义方法————要用赋值语句的形式+箭头函数 **
+	changeWeather = () =>{
+		const isHot = this.state.isHot
+		this.setState({isHot:!isHot})
+	}
+}
+//2.渲染组件到页面
+ReactDOM.render(<Weather/>,document.getElementById('test'))

props

jsx
//创建组件
+class Person extends React.Component{
+    //props简写形式: 对标签属性进行类型、必要性的限制
+    static propTypes = {
+        name:PropTypes.string.isRequired, //限制name必传,且为字符串
+        sex:PropTypes.string,//限制sex为字符串
+        age:PropTypes.number,//限制age为数值
+	}
+	render(){
+		const {name,age,sex} = this.props
+		return (
+			<ul>
+				<li>姓名:{name}</li>
+				<li>性别:{sex}</li>
+				<li>年龄:{age+1}</li>
+			</ul>
+		)
+	}
+}
+ 
+/*Person.propTypes = {
+	name:PropTypes.string.isRequired, //限制name必传,且为字符串
+	sex:PropTypes.string,//限制sex为字符串
+	age:PropTypes.number,//限制age为数值
+	speak:PropTypes.func,//限制speak为函数
+}
+
+Person.defaultProps = {//指定默认标签属性值
+	sex:'男',//sex默认值为男
+	age:18 //age默认值为18
+}*/
+//渲染组件到页面
+ReactDOM.render(<Person name="jerry" age={19}  sex=""/>,document.getElementById('test1'))
+ReactDOM.render(<Person name="tom" age={18} sex=""/>,document.getElementById('test2'))
+
+const p = {name:'老刘',age:18,sex:''}
+// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
+ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
//创建组件
+class Person extends React.Component{
+    //props简写形式: 对标签属性进行类型、必要性的限制
+    static propTypes = {
+        name:PropTypes.string.isRequired, //限制name必传,且为字符串
+        sex:PropTypes.string,//限制sex为字符串
+        age:PropTypes.number,//限制age为数值
+	}
+	render(){
+		const {name,age,sex} = this.props
+		return (
+			<ul>
+				<li>姓名:{name}</li>
+				<li>性别:{sex}</li>
+				<li>年龄:{age+1}</li>
+			</ul>
+		)
+	}
+}
+ 
+/*Person.propTypes = {
+	name:PropTypes.string.isRequired, //限制name必传,且为字符串
+	sex:PropTypes.string,//限制sex为字符串
+	age:PropTypes.number,//限制age为数值
+	speak:PropTypes.func,//限制speak为函数
+}
+
+Person.defaultProps = {//指定默认标签属性值
+	sex:'男',//sex默认值为男
+	age:18 //age默认值为18
+}*/
+//渲染组件到页面
+ReactDOM.render(<Person name="jerry" age={19}  sex=""/>,document.getElementById('test1'))
+ReactDOM.render(<Person name="tom" age={18} sex=""/>,document.getElementById('test2'))
+
+const p = {name:'老刘',age:18,sex:''}
+// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
+ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))

函数组件使用props

jsx
function Person (props){
+	const {name,age,sex} = props
+	return (
+        <ul>
+            <li>姓名:{name}</li>
+            <li>性别:{sex}</li>
+            <li>年龄:{age}</li>
+        </ul>
+	)
+}
+Person.propTypes = {
+	name:PropTypes.string.isRequired, 
+	sex:PropTypes.string,
+	age:PropTypes.number,
+}
+
+Person.defaultProps = {
+	sex:'',
+	age:18 
+}
function Person (props){
+	const {name,age,sex} = props
+	return (
+        <ul>
+            <li>姓名:{name}</li>
+            <li>性别:{sex}</li>
+            <li>年龄:{age}</li>
+        </ul>
+	)
+}
+Person.propTypes = {
+	name:PropTypes.string.isRequired, 
+	sex:PropTypes.string,
+	age:PropTypes.number,
+}
+
+Person.defaultProps = {
+	sex:'',
+	age:18 
+}

refs

jsx
class Demo extends React.Component{
+    myRef2 = React.createRef() //3.createRef形式
+    //React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
+    
+	showData = ()=>{
+		const {input1} = this.refs //1.字符串形式
+        const {input2} = this //2.回调函数形式
+	}
+    saveInput = (c)=>{
+        this.input2 = c;
+        console.log('=@=',c);
+    }
+	render(){
+		return(
+			<div>
+				<input ref="input1" type="text"/> {/*字符串形式*/}
+			  	<input ref={(c)=>{this.input2 = c;console.log('@',c);}} type="text"/> {/*回调函数形式*/}
+               	<input ref={this.saveInput} type="text"/>
+                <input ref={this.myRef} type="text" />{/*createRef形式*/}
+			</div>
+		)
+	}
+}
+ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))
class Demo extends React.Component{
+    myRef2 = React.createRef() //3.createRef形式
+    //React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
+    
+	showData = ()=>{
+		const {input1} = this.refs //1.字符串形式
+        const {input2} = this //2.回调函数形式
+	}
+    saveInput = (c)=>{
+        this.input2 = c;
+        console.log('=@=',c);
+    }
+	render(){
+		return(
+			<div>
+				<input ref="input1" type="text"/> {/*字符串形式*/}
+			  	<input ref={(c)=>{this.input2 = c;console.log('@',c);}} type="text"/> {/*回调函数形式*/}
+               	<input ref={this.saveInput} type="text"/>
+                <input ref={this.myRef} type="text" />{/*createRef形式*/}
+			</div>
+		)
+	}
+}
+ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))

注意: 回调函数形式执行次数

事件处理

WARNING

(1).通过onXxx属性指定事件处理函数(注意大小写)

​ a. React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性

​ b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效

(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref

高阶函数:参数或返回值是一个函数满足一个条件则为高阶函数。

​ 常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

js
function sum(a){
+	return(b)=>{
+		return (c)=>{
+			return a+b+c
+		}
+	}
+}
+//函数柯里化传参
+saveFormData = (dataType)=>{
+	return (event)=>{
+		this.setState({[dataType]:event.target.value})
+	}
+}
+//<input onChange={this.saveFormData('username')} type="text" name="username"/>
+
+//箭头函数传参
+saveFormData = (dataType,event)=>{
+        this.setState({[dataType]:event.target.value})
+    }
+//<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
function sum(a){
+	return(b)=>{
+		return (c)=>{
+			return a+b+c
+		}
+	}
+}
+//函数柯里化传参
+saveFormData = (dataType)=>{
+	return (event)=>{
+		this.setState({[dataType]:event.target.value})
+	}
+}
+//<input onChange={this.saveFormData('username')} type="text" name="username"/>
+
+//箭头函数传参
+saveFormData = (dataType,event)=>{
+        this.setState({[dataType]:event.target.value})
+    }
+//<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>

组件生命周期

旧版(16)

image-20220421223156627

js
/* 
+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	componentWillMount()
+            3.	render()
+            4.	componentDidMount() =====> 常用
+            一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+            
+2. 更新阶段: 由组件内部this.setSate()或父组件render触发
+            1.	shouldComponentUpdate()
+            2.	componentWillUpdate()
+            3.	render() =====> 必须使用的一个
+            4.	componentDidUpdate()
+            
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+            一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
+*/
/* 
+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	componentWillMount()
+            3.	render()
+            4.	componentDidMount() =====> 常用
+            一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+            
+2. 更新阶段: 由组件内部this.setSate()或父组件render触发
+            1.	shouldComponentUpdate()
+            2.	componentWillUpdate()
+            3.	render() =====> 必须使用的一个
+            4.	componentDidUpdate()
+            
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+            一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
+*/

新版(17+)

image-20220421223604701

markdown

+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	getDerivedStateFromProps
+            3.	render()
+            4.	componentDidMount() =====> 常用
+                        一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
+            1.	getDerivedStateFromProps
+            2.	shouldComponentUpdate()
+            3.	render()
+            4.	getSnapshotBeforeUpdate
+            5.	componentDidUpdate()
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+                        一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	getDerivedStateFromProps
+            3.	render()
+            4.	componentDidMount() =====> 常用
+                        一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
+            1.	getDerivedStateFromProps
+            2.	shouldComponentUpdate()
+            3.	render()
+            4.	getSnapshotBeforeUpdate
+            5.	componentDidUpdate()
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+                        一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

getSnapshotBeforeUpdate

在render之前调用,state已更新

典型场景:获取render之前的dom状态

getDerivedStateFromProps

TIP

1:当state需要从props初始化时,使用

2:尽量不使用,维护俩者状态需要消耗额外资源,增加复杂度

3:每次render都会调用

4:典型场景表单获取默认值

markdown
 面试相关题:
+	1). react/vue中的key有什么作用?(key的内部原理是什么?)
+	2). 为什么遍历列表时,key最好不要用index?
+
+1. 虚拟DOM中key的作用:
+	1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
+
+	2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 
+                    随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
+
+        a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
+                    (1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
+                    (2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
+
+        b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
+                    根据数据创建新的真实DOM,随后渲染到到页面
+
+2. 用index作为key可能会引发的问题:
+    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
+                    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
+
+    2. 如果结构中还包含输入类的DOM:
+                    会产生错误DOM更新 ==> 界面有问题。
+
+    3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
+        仅用于渲染列表用于展示,使用index作为key是没有问题的。
+
+3. 开发中如何选择key?:
+    1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
+    2.如果确定只是简单的展示数据,用index也是可以的。
 面试相关题:
+	1). react/vue中的key有什么作用?(key的内部原理是什么?)
+	2). 为什么遍历列表时,key最好不要用index?
+
+1. 虚拟DOM中key的作用:
+	1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
+
+	2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 
+                    随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
+
+        a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
+                    (1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
+                    (2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
+
+        b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
+                    根据数据创建新的真实DOM,随后渲染到到页面
+
+2. 用index作为key可能会引发的问题:
+    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
+                    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
+
+    2. 如果结构中还包含输入类的DOM:
+                    会产生错误DOM更新 ==> 界面有问题。
+
+    3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
+        仅用于渲染列表用于展示,使用index作为key是没有问题的。
+
+3. 开发中如何选择key?:
+    1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
+    2.如果确定只是简单的展示数据,用index也是可以的。
+ + + + \ No newline at end of file diff --git "a/Framework/Vue/Vite\345\216\237\347\220\206\345\255\246\344\271\240.html" "b/Framework/Vue/Vite\345\216\237\347\220\206\345\255\246\344\271\240.html" new file mode 100644 index 00000000..91502cba --- /dev/null +++ "b/Framework/Vue/Vite\345\216\237\347\220\206\345\255\246\344\271\240.html" @@ -0,0 +1,31 @@ + + + + + + Vite底层原理学习 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Vite底层原理学习

构建工具承担:

  1. 模块化开发支持:ES Module、CommonJS、AMD、CMD等
  2. 处理代码兼容性:babel语法降级,less/sass/stylus等语法转换
  3. 提升项目性能:压缩代码,合并代码,图片压缩,代码分割,懒加载,预加载等
  4. 优化开发体验:热更新,自动刷新,代理服务器,自动打开浏览器等
  5. 统一开发标准:eslint代码检查,prettier代码格式化,git提交规范等
+ + + + \ No newline at end of file diff --git "a/Framework/Vue/Vue3\350\241\245\346\274\217\347\254\224\350\256\260.html" "b/Framework/Vue/Vue3\350\241\245\346\274\217\347\254\224\350\256\260.html" new file mode 100644 index 00000000..2dcb846d --- /dev/null +++ "b/Framework/Vue/Vue3\350\241\245\346\274\217\347\254\224\350\256\260.html" @@ -0,0 +1,127 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

inheritAttrs

唯一一个需要用额外的 script 块书写的选项

$attrs

透传 Attributes 是指由父组件传入,且没有被子组件声明为 props 或是 组件自定义事件的 attributes 和 事件处理函数。

html
<template> 
+  <Home :attr="12345" :val="false"/>
+</template>
<template> 
+  <Home :attr="12345" :val="false"/>
+</template>

场景一:

html
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: true,//默认继承父组件属性
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: true,//默认继承父组件属性
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>

image-20230219215449385

场景二:

html
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>

image-20230219215459359

场景三:

html
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)//输出被props接收以外的属性
+	  }
+    props: ['val']
+  }
+</script>
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)//输出被props接收以外的属性
+	  }
+    props: ['val']
+  }
+</script>

image-20230219215510922

+ + + + \ No newline at end of file diff --git "a/Framework/Vue/\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.html" "b/Framework/Vue/\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.html" new file mode 100644 index 00000000..592be1d9 --- /dev/null +++ "b/Framework/Vue/\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.html" @@ -0,0 +1,367 @@ + + + + + + 分页与搜索条件记录并回显优化 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

分页与搜索条件记录并回显优化

整体逻辑

image-20230215205106488

Store

js
export default new Vuex.Store({
+    state: {
+        pageOptions: {
+            background:true,
+            layout: 'prev, pager, next, jumper, sizes, total',
+            pageSizes: [10, 20, 30, 50]
+        },
+    }
+}
export default new Vuex.Store({
+    state: {
+        pageOptions: {
+            background:true,
+            layout: 'prev, pager, next, jumper, sizes, total',
+            pageSizes: [10, 20, 30, 50]
+        },
+    }
+}

Mixins

js
import { mapState } from 'vuex'
+export default {
+	data() {
+		return {
+			wrapperLoading: false,
+			gridLoading: false,
+			isEchoCond: false,//回显开关(某些页面特殊需要特殊处理)
+			searchConds: [],
+			paginationOptions: {
+				currentPage: 1,
+				pageSize: 10,
+				total: 0,
+			},
+		}
+	},
+  computed: {
+		...mapState(["pageOptions"]),
+	},
+	methods: {
+		//搜索
+		search(conds) {
+			this.searchConds = conds
+			const query = this.$route.query;
+			let newQuery = Object.assign({}, query, { conds: JSON.stringify(conds), page: 1 })
+			this.$router.push({
+				query: newQuery,
+		 });
+		},
+		//每页数量改变
+		sizeChange(size, queryFn) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { size, page: 1 }),
+			})
+		},
+		//页码改变
+		currentChange(page) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { page }),
+			})
+			this.paginationOptions.currentPage = page
+		},
+		//从query中获取分页信息
+    initPage(){
+			let { page, size ,conds} = this.$route.query
+      this.paginationOptions.currentPage = page ?  parseInt(page) : 1
+			this.paginationOptions.pageSize = size ?  parseInt(size) : 10
+			conds = conds ? conds : '[]';
+			if (this.isEchoCond) {
+				 this.searchConds = JSON.parse(conds);
+				 this.initSearchFromCond(this.searchConds);
+			 } 
+		},
+		//回显搜索条件
+		initSearchFromCond(conds) {
+      const group = [];
+      this.relateOptions?.forEach(options => {
+        const nameArr = options.list.map( item => item.name);
+				options.model.value = ''
+        group.push(nameArr);
+      });
+      conds.forEach(cond => {
+				group.forEach((g, i) => {
+					if(g.includes(cond.name)) {
+						const obj = {name: '', op: '', value: ''};
+						obj.name = cond.name;
+						obj.op = cond.op;
+						obj.value = cond.op === 'like' ? cond.value.replace(/^%|%$/g, '') : cond.value;
+						this.relateOptions[i].model = obj;
+					}
+				});
+      });
+    },
+	},
+}
import { mapState } from 'vuex'
+export default {
+	data() {
+		return {
+			wrapperLoading: false,
+			gridLoading: false,
+			isEchoCond: false,//回显开关(某些页面特殊需要特殊处理)
+			searchConds: [],
+			paginationOptions: {
+				currentPage: 1,
+				pageSize: 10,
+				total: 0,
+			},
+		}
+	},
+  computed: {
+		...mapState(["pageOptions"]),
+	},
+	methods: {
+		//搜索
+		search(conds) {
+			this.searchConds = conds
+			const query = this.$route.query;
+			let newQuery = Object.assign({}, query, { conds: JSON.stringify(conds), page: 1 })
+			this.$router.push({
+				query: newQuery,
+		 });
+		},
+		//每页数量改变
+		sizeChange(size, queryFn) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { size, page: 1 }),
+			})
+		},
+		//页码改变
+		currentChange(page) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { page }),
+			})
+			this.paginationOptions.currentPage = page
+		},
+		//从query中获取分页信息
+    initPage(){
+			let { page, size ,conds} = this.$route.query
+      this.paginationOptions.currentPage = page ?  parseInt(page) : 1
+			this.paginationOptions.pageSize = size ?  parseInt(size) : 10
+			conds = conds ? conds : '[]';
+			if (this.isEchoCond) {
+				 this.searchConds = JSON.parse(conds);
+				 this.initSearchFromCond(this.searchConds);
+			 } 
+		},
+		//回显搜索条件
+		initSearchFromCond(conds) {
+      const group = [];
+      this.relateOptions?.forEach(options => {
+        const nameArr = options.list.map( item => item.name);
+				options.model.value = ''
+        group.push(nameArr);
+      });
+      conds.forEach(cond => {
+				group.forEach((g, i) => {
+					if(g.includes(cond.name)) {
+						const obj = {name: '', op: '', value: ''};
+						obj.name = cond.name;
+						obj.op = cond.op;
+						obj.value = cond.op === 'like' ? cond.value.replace(/^%|%$/g, '') : cond.value;
+						this.relateOptions[i].model = obj;
+					}
+				});
+      });
+    },
+	},
+}

列表页 xxxList.vue

js
data() {
+	return {
+		relateOptions: [
+				{
+					inputWidth: "200px",
+					list: [
+						{
+							name: "number",
+							op: "=",
+							label: "序号",
+							placeholder: "情输入序号",
+						},
+						{
+							name: "name",
+							op: "like",
+							label: "名称",
+							placeholder: "请输入名称",
+						},
+						{
+							name: "esn",
+							op: "like",
+							label: "ESN",
+							placeholder: "请输入ESN",
+						},
+						{
+							name: "status.status",
+							op: "=",
+							label: "状态",
+							valueList: [
+								{
+									name: "",
+									label: "全部",
+								},
+								{
+									name: "Online",
+									label: "在线",
+								},
+								{
+									name: "Offline",
+									label: "离线",
+								},
+							],
+						},
+					],
+					model: { name: "number", op: "like", value: "" },
+				},
+			],
+}
+mixins: [listPage],
+watch: {
+		'$route.query':{
+      immediate:true,
+      deep:true,
+      handler(){
+					this.initPage()
+					this.queryXXX();
+      }
+    },
+	},
+    
+methods: {
+		async queryXXX() {
+			this.gridLoading = true
+		  const qobj = {}
+			qobj.conditions = this.searchConds
+      
+			let { pageSize, currentPage } = this.paginationOptions
+			qobj.limit = pageSize
+			qobj.start = (currentPage - 1) * pageSize
+
+			const result = await queryXXX(qobj)
+			if (result.success && result.inventories.length) {
+			this.xxxList = result.success ? result.inventories : []
+			this.paginationOptions.total = result.success ? result.total : 0
+			this.gridLoading = false
+		},
+		searchCondDone(conds) {
+			this.search(conds)
+		},
+		handleSizeChange(size) {
+			this.sizeChange(size)
+		},
+		handleCurrentChange(page) {
+		  this.currentChange(page)
+		},
+   }
data() {
+	return {
+		relateOptions: [
+				{
+					inputWidth: "200px",
+					list: [
+						{
+							name: "number",
+							op: "=",
+							label: "序号",
+							placeholder: "情输入序号",
+						},
+						{
+							name: "name",
+							op: "like",
+							label: "名称",
+							placeholder: "请输入名称",
+						},
+						{
+							name: "esn",
+							op: "like",
+							label: "ESN",
+							placeholder: "请输入ESN",
+						},
+						{
+							name: "status.status",
+							op: "=",
+							label: "状态",
+							valueList: [
+								{
+									name: "",
+									label: "全部",
+								},
+								{
+									name: "Online",
+									label: "在线",
+								},
+								{
+									name: "Offline",
+									label: "离线",
+								},
+							],
+						},
+					],
+					model: { name: "number", op: "like", value: "" },
+				},
+			],
+}
+mixins: [listPage],
+watch: {
+		'$route.query':{
+      immediate:true,
+      deep:true,
+      handler(){
+					this.initPage()
+					this.queryXXX();
+      }
+    },
+	},
+    
+methods: {
+		async queryXXX() {
+			this.gridLoading = true
+		  const qobj = {}
+			qobj.conditions = this.searchConds
+      
+			let { pageSize, currentPage } = this.paginationOptions
+			qobj.limit = pageSize
+			qobj.start = (currentPage - 1) * pageSize
+
+			const result = await queryXXX(qobj)
+			if (result.success && result.inventories.length) {
+			this.xxxList = result.success ? result.inventories : []
+			this.paginationOptions.total = result.success ? result.total : 0
+			this.gridLoading = false
+		},
+		searchCondDone(conds) {
+			this.search(conds)
+		},
+		handleSizeChange(size) {
+			this.sizeChange(size)
+		},
+		handleCurrentChange(page) {
+		  this.currentChange(page)
+		},
+   }
+ + + + \ No newline at end of file diff --git "a/Framework/Vue/\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.html" "b/Framework/Vue/\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.html" new file mode 100644 index 00000000..7ec92200 --- /dev/null +++ "b/Framework/Vue/\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.html" @@ -0,0 +1,109 @@ + + + + + + 一、删除最后一条数据跳转到上一页 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、删除最后一条数据跳转到上一页

方案一

js
/*
+paginationOptions: {
+    currentPage: 1,
+    pageSize: 10,
+    total: 0,
+},
+*/
+async removeDone() {
+    this.wrapperLoading = true
+    const { name, uuid } = this.currentRow
+    const { success } = await removeAccount({ uuid })
+    this.wrapperLoading = false
+    if (success) {
+        this.$notify({
+            type: "success",
+            message: `账号${name}删除成功`,
+        })
+        //方案一: 判断是否为最后一条数据 并且总数据不能小于1
+        let {total,currentPage} = this.paginationOptions.currentPage
+        	if (this.contactsData.length === 1 &&  total > 1) {
+            this.paginationOptions.currentPage = currentPage - 1
+        }
+        
+        //方案二:
+          let { currentPage,pageSize,total} = this.paginationOptions
+          //求删除后还有几页
+          let deleteAfterPage = Math.ceil((total - 1) / pageSize)
+          //若删除后页数小于当前页, 取删除后的页数;否则不变
+          let curPage = currentPage > deleteAfterPage ? deleteAfterPage : currentPage
+          //当前页只有一页则为1,否则取计算得到的页
+          this.paginationOptions.currentPage = curPage < 2 ? 1 : curPage
+        
+        this.queryAccount()
+    } else {
+        this.$notify({
+            type: "error",
+            message: `账号${name}删除失败`,
+        })
+    }
+},
/*
+paginationOptions: {
+    currentPage: 1,
+    pageSize: 10,
+    total: 0,
+},
+*/
+async removeDone() {
+    this.wrapperLoading = true
+    const { name, uuid } = this.currentRow
+    const { success } = await removeAccount({ uuid })
+    this.wrapperLoading = false
+    if (success) {
+        this.$notify({
+            type: "success",
+            message: `账号${name}删除成功`,
+        })
+        //方案一: 判断是否为最后一条数据 并且总数据不能小于1
+        let {total,currentPage} = this.paginationOptions.currentPage
+        	if (this.contactsData.length === 1 &&  total > 1) {
+            this.paginationOptions.currentPage = currentPage - 1
+        }
+        
+        //方案二:
+          let { currentPage,pageSize,total} = this.paginationOptions
+          //求删除后还有几页
+          let deleteAfterPage = Math.ceil((total - 1) / pageSize)
+          //若删除后页数小于当前页, 取删除后的页数;否则不变
+          let curPage = currentPage > deleteAfterPage ? deleteAfterPage : currentPage
+          //当前页只有一页则为1,否则取计算得到的页
+          this.paginationOptions.currentPage = curPage < 2 ? 1 : curPage
+        
+        this.queryAccount()
+    } else {
+        this.$notify({
+            type: "error",
+            message: `账号${name}删除失败`,
+        })
+    }
+},
+ + + + \ No newline at end of file diff --git "a/FrontEnd/CSS/Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.html" "b/FrontEnd/CSS/Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.html" new file mode 100644 index 00000000..1a156c78 --- /dev/null +++ "b/FrontEnd/CSS/Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.html" @@ -0,0 +1,265 @@ + + + + + + Grid布局学习笔记 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Grid布局学习笔记

实用网站

基本概念

image-20230216202917923

image-20230216203121127

容器属性

开启 Grid布局

css
.box{
+  display:grid;
+}
.box{
+  display:grid;
+}

容器划分行列

  1. 取值为数值 grid-template-rows:100px 100px 100px
  2. 取值为百分比 grid-template-rows:20% 30% 50%
  3. 重复函数 grid-template-rows:repeat(3,20%)
  4. 自动填充 grid-template-rows:repeat(auto-fill, 30%)
  5. auto自动 grid-template-rows:100px auto 100px
  6. fr片段划分 grid-template-rows:1fr 2fr 1fr
  7. minmax() grid-template-rows:200px 200px minmax(100px,200px)

image-20230216205607291

image-20230216205635684

image-20230216205710712

image-20230216205031540

image-20230216205043840

image-20230216205247964

image-20230216205743766

调整间距属性

css
.box{
+  /* 写法一:*/
+  grid-row-gap:20px;
+  grid-column-gap:30px;
+
+   /* 写法二:*/
+  grid-gap:20px 30px;
+
+   /* 写法三:*/
+  gap:20px 30px;
+
+}
.box{
+  /* 写法一:*/
+  grid-row-gap:20px;
+  grid-column-gap:30px;
+
+   /* 写法二:*/
+  grid-gap:20px 30px;
+
+   /* 写法三:*/
+  gap:20px 30px;
+
+}

image-20230216210259623

容器内网格对齐方式

解释

网格相对于容器的对齐方式

css
.box{
+  /*justify-content:space-around;
+  align-content:space-evenly;*/
+  palce-content:space-around space-evenly;
+}
.box{
+  /*justify-content:space-around;
+  align-content:space-evenly;*/
+  palce-content:space-around space-evenly;
+}

image-20230216212726986

案例

css
.box{
+  justify-content:center; 
+   align-content: center;
+}
.box{
+  justify-content:center; 
+   align-content: center;
+}

image-20230216223101040

网格内项目对其方式

解释

项目相对于网格/区域的对齐方式

js
.box{
+  justify-items:center;    //start, end
+  align-items:center;    //start, end
+  //place-items:center center //水平 垂直
+}
.box{
+  justify-items:center;    //start, end
+  align-items:center;    //start, end
+  //place-items:center center //水平 垂直
+}

image-20230216211850992

案例:

html
 <div class="box">
+      <div class="item a"></div>
+      <div class="item b"></div>
+      <div class="item c"></div>
+    </div>
 <div class="box">
+      <div class="item a"></div>
+      <div class="item b"></div>
+      <div class="item c"></div>
+    </div>
css
     .box {
+        width: 800px;
+        height: 800px;
+        display: grid;
+        grid-template-columns: repeat(3, 100px);
+        grid-template-rows: repeat(3, 100px);
+        align-items: center;
+        justify-items: center;
+        grid-gap: 10px;
+        grid-template-areas:
+          "a a a"
+          ". b b"
+          "c c c";
+      }
+      .item{
+        width: 50px ;
+        height: 50px;
+        border:1px dashed #000;
+
+      }
+      .a{
+        grid-area: a;
+      }
+      .b{
+        grid-area: b;
+      }
+      .c{
+        grid-area: c;
+      }
     .box {
+        width: 800px;
+        height: 800px;
+        display: grid;
+        grid-template-columns: repeat(3, 100px);
+        grid-template-rows: repeat(3, 100px);
+        align-items: center;
+        justify-items: center;
+        grid-gap: 10px;
+        grid-template-areas:
+          "a a a"
+          ". b b"
+          "c c c";
+      }
+      .item{
+        width: 50px ;
+        height: 50px;
+        border:1px dashed #000;
+
+      }
+      .a{
+        grid-area: a;
+      }
+      .b{
+        grid-area: b;
+      }
+      .c{
+        grid-area: c;
+      }

image-20230216222635254

项目排列顺序

image-20230216210624604

容器中区域定义

html
<div class="box">
+  <div class="item a"></div>
+  <div class="item b"></div>
+  <div class="item c"></div>
+</div>
<div class="box">
+  <div class="item a"></div>
+  <div class="item b"></div>
+  <div class="item c"></div>
+</div>
css
.box {
+    width: 800px;
+    height: 800px;
+    display: grid;
+    grid-template-columns: repeat(3, 100px);
+    grid-template-rows: repeat(3, 100px);
+    align-content: center;
+    justify-content: center;
+    grid-gap: 10px;
+    grid-template-areas:
+      "a a a"
+      ". b b"
+      "c c c";
+  }
+  .item{
+    border:1px dashed #000;
+  }
+  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }
.box {
+    width: 800px;
+    height: 800px;
+    display: grid;
+    grid-template-columns: repeat(3, 100px);
+    grid-template-rows: repeat(3, 100px);
+    align-content: center;
+    justify-content: center;
+    grid-gap: 10px;
+    grid-template-areas:
+      "a a a"
+      ". b b"
+      "c c c";
+  }
+  .item{
+    border:1px dashed #000;
+  }
+  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }

image-20230216220606952

项目属性

合并单元格属性

css
.header{
+  /* 写法一:*/
+  grid-column-start: 1;
+  grid-column-end: 3;
+
+  grid-row-start: 1;
+  grid-row-end: 2;
+
+  /* 写法二:*/
+  grid-column: 1 / 3;
+  grid-row: 1 / 2;
+
+  /* 写法三:使用 span 关键字,表示跨越。表示项目的左边框距离右边框跨越 2 个网格。*/
+  grid-column-start: span 2;
+
+  /* 写法四:若跨度为 1,则可简写第二根网格线*/
+  grid-row: 1 / 2; ==>  grid-row: 1;
+  grid-row: 3 / 4; ==>  grid-row: 3;
+}
.header{
+  /* 写法一:*/
+  grid-column-start: 1;
+  grid-column-end: 3;
+
+  grid-row-start: 1;
+  grid-row-end: 2;
+
+  /* 写法二:*/
+  grid-column: 1 / 3;
+  grid-row: 1 / 2;
+
+  /* 写法三:使用 span 关键字,表示跨越。表示项目的左边框距离右边框跨越 2 个网格。*/
+  grid-column-start: span 2;
+
+  /* 写法四:若跨度为 1,则可简写第二根网格线*/
+  grid-row: 1 / 2; ==>  grid-row: 1;
+  grid-row: 3 / 4; ==>  grid-row: 3;
+}

image-20230216213656308

项目区域定义

css
  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }
  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }

grid-area

grid-area 属性还可用作 grid-row-startgrid-column-startgrid-row-endgrid-column-end 的合并简写形式,直接指定项目的位置。

css
.item {
+  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
+}
.item {
+  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
+}

单个项目位置

justify-self 和 align-self

justify-self 属性设置单元格内容的水平位置(左中右),跟 justify-items 属性的用法完全一致,但只作用于单个项目。

align-self 属性设置单元格内容的垂直位置(上中下),跟 align-items 属性的用法完全一致,也是只作用于单个项目。

css
.item {
+  justify-self: start | end | center | stretch;
+  align-self: start | end | center | stretch;
+  /* 简写 place-self: <align-self> <justify-self>; */
+}
.item {
+  justify-self: start | end | center | stretch;
+  align-self: start | end | center | stretch;
+  /* 简写 place-self: <align-self> <justify-self>; */
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/CSS/\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.html" "b/FrontEnd/CSS/\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.html" new file mode 100644 index 00000000..15547eaa --- /dev/null +++ "b/FrontEnd/CSS/\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.html" @@ -0,0 +1,205 @@ + + + + + + CSS常用代码段 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

CSS常用代码段

单行与多行溢出隐藏

css
.text {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
.text {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
css
.text {
+    display: -webkit-box;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -webkit-box-orient: vertical;/* 布局方向 */
+    -webkit-line-clamp: 3; /* 显示三行文本 */
+}
.text {
+    display: -webkit-box;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -webkit-box-orient: vertical;/* 布局方向 */
+    -webkit-line-clamp: 3; /* 显示三行文本 */
+}

自定义滚动条

css
html,
+body {
+  /* 隐藏滚动条 */
+  scrollbar-width: none; /* firefox */
+  -ms-overflow-style: none; /* IE 10+ */
+  &::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+}
+
+ /* 自定义滚动条 */
+body{
+  overflow: auto;
+  scrollbar-width: none; /* Firefox */
+  &::-webkit-scrollbar {
+    width: 5px;
+    height: 5px;
+  }
+  &::-webkit-scrollbar-track-piece {
+    background-color: rgba($color: #000000, $alpha: .3);
+  }
+  &::-webkit-scrollbar-thumb:vertical {
+    height: 5px;
+    background-color: #0085F9;
+    border-radius: 6px;
+  }
+}
html,
+body {
+  /* 隐藏滚动条 */
+  scrollbar-width: none; /* firefox */
+  -ms-overflow-style: none; /* IE 10+ */
+  &::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+}
+
+ /* 自定义滚动条 */
+body{
+  overflow: auto;
+  scrollbar-width: none; /* Firefox */
+  &::-webkit-scrollbar {
+    width: 5px;
+    height: 5px;
+  }
+  &::-webkit-scrollbar-track-piece {
+    background-color: rgba($color: #000000, $alpha: .3);
+  }
+  &::-webkit-scrollbar-thumb:vertical {
+    height: 5px;
+    background-color: #0085F9;
+    border-radius: 6px;
+  }
+}

画布网状满天星背景

html
<svg >
+  <pattern
+    id="pattern-1"
+    x="0"
+    y="0"
+    width="24"
+    height="24"
+    patternUnits="userSpaceOnUse"
+    patternTransform="translate(-0.5,-0.5)"
+  >
+    <circle cx="0.5" cy="0.5" r="0.5" fill="#60606F"></circle>
+  </pattern>
+  <rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-1)"></rect>
+</svg>
<svg >
+  <pattern
+    id="pattern-1"
+    x="0"
+    y="0"
+    width="24"
+    height="24"
+    patternUnits="userSpaceOnUse"
+    patternTransform="translate(-0.5,-0.5)"
+  >
+    <circle cx="0.5" cy="0.5" r="0.5" fill="#60606F"></circle>
+  </pattern>
+  <rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-1)"></rect>
+</svg>
css
svg {
+  margin-top: 20px;
+  width: 100%;
+  height: 200px;
+  background-color:#13121a;
+}
svg {
+  margin-top: 20px;
+  width: 100%;
+  height: 200px;
+  background-color:#13121a;
+}

轮播闪光

css
.shine::before {
+  content: '';
+  position: absolute;
+  top: -50%;
+  left: -50%;
+  width: 200%;
+  height: 200%;
+  background: linear-gradient(to bottom right,
+      rgba(255, 255, 255, 0.3),
+      rgba(255, 255, 255, 0.15),
+      rgba(255, 255, 255, 0));
+  transform: rotate(-45deg);
+  animation: shine 2s ease-in-out infinite;
+}
+
+@keyframes shine {
+  from {
+    left: -200%;
+  }
+
+  to {
+    left: 150%;
+  }
+
+}
.shine::before {
+  content: '';
+  position: absolute;
+  top: -50%;
+  left: -50%;
+  width: 200%;
+  height: 200%;
+  background: linear-gradient(to bottom right,
+      rgba(255, 255, 255, 0.3),
+      rgba(255, 255, 255, 0.15),
+      rgba(255, 255, 255, 0));
+  transform: rotate(-45deg);
+  animation: shine 2s ease-in-out infinite;
+}
+
+@keyframes shine {
+  from {
+    left: -200%;
+  }
+
+  to {
+    left: 150%;
+  }
+
+}

flex布局子元素给了高度,实际渲染确有小数点问题

css
.parent{
+  display: flex;
+  flex-direction: column;
+}
+.child{
+  height: 100%;
+}
+.child1{
+    flex: 1; //需要给相邻元素添加
+}
.parent{
+  display: flex;
+  flex-direction: column;
+}
+.child{
+  height: 100%;
+}
+.child1{
+    flex: 1; //需要给相邻元素添加
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/CSS/\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.html" "b/FrontEnd/CSS/\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.html" new file mode 100644 index 00000000..4969b908 --- /dev/null +++ "b/FrontEnd/CSS/\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.html" @@ -0,0 +1,371 @@ + + + + + + 妙妙怪的《CSS 揭秘》读书摘要 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

妙妙怪的《CSS 揭秘》读书摘要

看这本书前:看书,现在短视频时代,正经人谁看书啊,要看也是看视频教程和大佬博客啊!

看完这本后:似乎有一点香!(轻松有趣)

从这本书字里行间可以感受到作者也是个有趣的灵魂。

看了这本书知识浅显易懂、挺有趣的,重新让我拾回看书的一些兴趣;

这本书让我感受到 CSS 一些巧妙的技巧,故摘抄以便往后快捷运用。

背景与边框

多重边框

css
box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink, 0 2px 5px 15px #ccc;
box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink, 0 2px 5px 15px #ccc;

image-20230204162420066

灵活的背景定位

css
background-position:right 20px bottom 10px;//离右侧20px、下边10px
+background-position:calc(100%-20px) calc(100%-10px);
+background-origin:content-box;//以内容盒为准
background-position:right 20px bottom 10px;//离右侧20px、下边10px
+background-position:calc(100%-20px) calc(100%-10px);
+background-origin:content-box;//以内容盒为准

边框内圆角

css
background: tan;
+border-radius: .8em;
+padding: 1em;
+box-shadow: 0 0 0 .4em #655;//扩张半径取圆角的一半
+outline: .4em solid #655;
background: tan;
+border-radius: .8em;
+padding: 1em;
+box-shadow: 0 0 0 .4em #655;//扩张半径取圆角的一半
+outline: .4em solid #655;

条纹背景

css
//横向
+background: linear-gradient(#fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 100% 20px;
+//垂直
+background: linear-gradient(to right, #fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 20px 100%;
+//斜向
+background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #ccc 0, #ccc 75%, #58a 0);
+background-size: 100%;
+//重复任意角度条纹
+ background: repeating-linear-gradient( 60deg, #fb3, #fb3 15px, #58a 0, #58a 30px);
//横向
+background: linear-gradient(#fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 100% 20px;
+//垂直
+background: linear-gradient(to right, #fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 20px 100%;
+//斜向
+background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #ccc 0, #ccc 75%, #58a 0);
+background-size: 100%;
+//重复任意角度条纹
+ background: repeating-linear-gradient( 60deg, #fb3, #fb3 15px, #58a 0, #58a 30px);

image-20230204162605711

形状

圆角

css
border-radius:水平半径/垂直半径 
+border-radius: 50% / 100% 0;//树叶形状   
+border-radius: 100% 0 0 100%/50%; //半椭圆
+border-radius: 100% 0 0 0;//四分之一椭圆
border-radius:水平半径/垂直半径 
+border-radius: 50% / 100% 0;//树叶形状   
+border-radius: 100% 0 0 100%/50%; //半椭圆
+border-radius: 100% 0 0 0;//四分之一椭圆

image-20230204162727674

平行四边形

css
/*按钮内容不行变解决方案*/
+button {
+        position: relative;
+        background: transparent;
+        outline: none;
+        border: none;
+        padding: 10px 20px;
+        margin-left: 50px;
+        z-index: 1;
+    }
+
+    button::after {
+        position: absolute;
+        content: '';
+        top: 0;
+        left: 0;
+        bottom: 0;
+        right: 0;
+        width: 90px;
+        height: 35px;
+        display: block;
+        background: #5C7AEA;
+        transform: skewX(-30deg);
+        z-index: -1;
+    }
/*按钮内容不行变解决方案*/
+button {
+        position: relative;
+        background: transparent;
+        outline: none;
+        border: none;
+        padding: 10px 20px;
+        margin-left: 50px;
+        z-index: 1;
+    }
+
+    button::after {
+        position: absolute;
+        content: '';
+        top: 0;
+        left: 0;
+        bottom: 0;
+        right: 0;
+        width: 90px;
+        height: 35px;
+        display: block;
+        background: #5C7AEA;
+        transform: skewX(-30deg);
+        z-index: -1;
+    }

image-20230204162908289

梯形

css
.box {
+    width: 100px;
+    height: 100px;
+    background: rgb(52, 199, 155);
+    margin: 200px auto;
+    position: relative;
+    font-size: 40px;
+    color: #fff;
+    line-height: 100px;
+}
+.box::before {
+    position: absolute;
+    top: -100px;
+    left: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}
+.box::after {
+    position: absolute;
+    top: -100px;
+    right: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}
.box {
+    width: 100px;
+    height: 100px;
+    background: rgb(52, 199, 155);
+    margin: 200px auto;
+    position: relative;
+    font-size: 40px;
+    color: #fff;
+    line-height: 100px;
+}
+.box::before {
+    position: absolute;
+    top: -100px;
+    left: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}
+.box::after {
+    position: absolute;
+    top: -100px;
+    right: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}

image-20230204163212947

视觉效果

投影大致原理: box-shadow: 2px 3px 4px rgba(0, 0, 0, .5);

  1. 画该元素相同尺寸、位置、指定颜色的矩形
  2. 按指定的 x、y 进行水平垂直位移
  3. 按指定模糊半径,使用高斯模糊算法进行处理
  4. 切除与原始元素交集部分

双侧投影

css
box-shadow: 5px 0 5px -5px #000,-5px 0 5px -5px red
box-shadow: 5px 0 5px -5px #000,-5px 0 5px -5px red

image-20230204163300223

染色效果

css
img {
+    filter: sepia(1) saturate( 4) hue-rotate( 295deg);
+}
img {
+    filter: sepia(1) saturate( 4) hue-rotate( 295deg);
+}

image-20230204163621777

毛玻璃

IE 不支持 Chrome 大于等于 76 Edge 大于等于 17 Firefox 70 至 94

折角效果

css
box {
+            width: 200px;
+            height: 100px;
+            margin: 100px;
+            padding: 20px;
+            position: relative;
+                 border-radius: .5em;
+            background: linear-gradient(210deg, transparent 1.5em, #edb21d);
+        }
+
+        .box::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            right: 0;
+            width: 1.73em;
+            height: 3em;
+            background: linear-gradient(240deg, transparent 50%, #ccc);
+            transform: translateY(-1.3em) rotate(-30deg);
+            transform-origin: bottom right;
+            border-bottom-left-radius: inherit;
+            box-shadow: -0.3em 0.2em 0.3em -0.1em #bbb;
+        }
box {
+            width: 200px;
+            height: 100px;
+            margin: 100px;
+            padding: 20px;
+            position: relative;
+                 border-radius: .5em;
+            background: linear-gradient(210deg, transparent 1.5em, #edb21d);
+        }
+
+        .box::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            right: 0;
+            width: 1.73em;
+            height: 3em;
+            background: linear-gradient(240deg, transparent 50%, #ccc);
+            transform: translateY(-1.3em) rotate(-30deg);
+            transform-origin: bottom right;
+            border-bottom-left-radius: inherit;
+            box-shadow: -0.3em 0.2em 0.3em -0.1em #bbb;
+        }

折角效果 mixin 预处理器

css
@mixin folded-corner($background,$size,$angle:30deg){
+    position:relative;
+    background:$background;
+    background:linear-gradient($angle - 180deg,
+        transparent $size,$background 0);
+    border-radius: .5em;
+    $x:$size / sin($angle);
+    $y:$size / cos($angle);
+
+&::before{
+    content: '';
+    position: absolute;
+    top: 0;right: 0;
+    background: linear-gradient(to left bottom,
+        transparent 50%,
+        rgba(0,0,0,.2) 0,
+        rgba(0,0,0,.4)) 100% 0 no-repeat;
+    width:$y;height:$x;
+    transform:translateY($y-$x) rotate(2*$angle - 90deg);
+    transform-origin:bottom right;
+    border-bottom-left-radius:inherit;
+    box-shadow:-.2em .2em .3em -.1em rgba(0,0,0,.15);
+}
+}
+/*当调用时...*/
+.note{
+    @include folded-corner(#68d,1.3em,60deg);
+}
@mixin folded-corner($background,$size,$angle:30deg){
+    position:relative;
+    background:$background;
+    background:linear-gradient($angle - 180deg,
+        transparent $size,$background 0);
+    border-radius: .5em;
+    $x:$size / sin($angle);
+    $y:$size / cos($angle);
+
+&::before{
+    content: '';
+    position: absolute;
+    top: 0;right: 0;
+    background: linear-gradient(to left bottom,
+        transparent 50%,
+        rgba(0,0,0,.2) 0,
+        rgba(0,0,0,.4)) 100% 0 no-repeat;
+    width:$y;height:$x;
+    transform:translateY($y-$x) rotate(2*$angle - 90deg);
+    transform-origin:bottom right;
+    border-bottom-left-radius:inherit;
+    box-shadow:-.2em .2em .3em -.1em rgba(0,0,0,.15);
+}
+}
+/*当调用时...*/
+.note{
+    @include folded-corner(#68d,1.3em,60deg);
+}

字体排印

插入换行

css
hyphens:manual; / *手工设定。默认值,只有单词中有建议换行符才会换行,即手工在单词中插入 ­ * /
+hyphens:none; / *无。即使单词中有换行符,也不会换行,只会在空白处换行* /
+hyphens:auto; / *自动。浏览器在适当的位置自动插入连字符换行* /
hyphens:manual; / *手工设定。默认值,只有单词中有建议换行符才会换行,即手工在单词中插入 ­ * /
+hyphens:none; / *无。即使单词中有换行符,也不会换行,只会在空白处换行* /
+hyphens:auto; / *自动。浏览器在适当的位置自动插入连字符换行* /

可以结合选择器 + / ~ / not(:first-child) 实现在元素后面添加 ,/ 换行符

css
dd+dt::before{
+    content:'\A';
+    /*content:',';*/
+    white-space:pre;/*空白会被浏览器保留*/
+
+}
dd+dt::before{
+    content:'\A';
+    /*content:',';*/
+    white-space:pre;/*空白会被浏览器保留*/
+
+}

文本行斑马线

css
.box{
+     padding: 0 .5em;
+    line-height: 1.2;
+    background: hsl(184, 61%, 76%);
+    background-image: linear-gradient( rgb(230, 230, 230) 50%, transparent 0);
+    background-size: auto 50%;
+    background-origin: content-box;
+    font-family: Consolas, Monaco, monospace;
+}
.box{
+     padding: 0 .5em;
+    line-height: 1.2;
+    background: hsl(184, 61%, 76%);
+    background-image: linear-gradient( rgb(230, 230, 230) 50%, transparent 0);
+    background-size: auto 50%;
+    background-origin: content-box;
+    font-family: Consolas, Monaco, monospace;
+}

image-20230204164506163

自定义下划线

css
.box{
+    background: linear-gradient(gray, gray) no-repeat;
+    background-size: 100% 1px;
+    background-position: 0 1.15em;
+    text-shadow: .05em 0 white, -.05em 0 white;
+}
.box{
+    background: linear-gradient(gray, gray) no-repeat;
+    background-size: 100% 1px;
+    background-position: 0 1.15em;
+    text-shadow: .05em 0 white, -.05em 0 white;
+}

image-20230204164714672

凹凸印刷文字效果

css
text-shadow: 1px 1px 1px #000, -1px -1px 1px #fff;//凸
+text-shadow: -1px -1px 1px #000, 1px 1px 1px #fff;//凹
text-shadow: 1px 1px 1px #000, -1px -1px 1px #fff;//凸
+text-shadow: -1px -1px 1px #000, 1px 1px 1px #fff;//凹

image-20230204165035803

满幅背景、定宽内容(页脚)

css
footer{
+    max-width:1000px;
+    padding:1em calc(50%-500px)
+}
footer{
+    max-width:1000px;
+    padding:1em calc(50%-500px)
+}

紧贴底部的页脚

css
body{
+    display:flex;
+    flex-direction:column;
+    min-height:100vh;
+}
+main{
+    flex:1;
+}
body{
+    display:flex;
+    flex-direction:column;
+    min-height:100vh;
+}
+main{
+    flex:1;
+}

闪烁效果

css
.box{
+  background-color:  pink;
+  animation: twinkle 0.5s infinite steps(2) alternate;/*普通闪烁*/
+  animation: twinkle 0.5s infinite   alternate;  /*真实闪烁*/
+}
+@keyframes twinkle {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}
.box{
+  background-color:  pink;
+  animation: twinkle 0.5s infinite steps(2) alternate;/*普通闪烁*/
+  animation: twinkle 0.5s infinite   alternate;  /*真实闪烁*/
+}
+@keyframes twinkle {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}

2023-02-04 16.57.27

+ + + + \ No newline at end of file diff --git "a/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.html" "b/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.html" new file mode 100644 index 00000000..ebd854df --- /dev/null +++ "b/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.html" @@ -0,0 +1,145 @@ + + + + + + Git常用操作 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Git常用操作

拉取最新提交

zsh
  git fetch -p  #或 git fetch -p origin
  git fetch -p  #或 git fetch -p origin

git fetch -p (或者 --prune)命令用于从远程仓库中拉取最新的提交记录,同时也会删除 本地不存在的远程分支;不会更新本地分支和远程分支之间的关联关系,需要手动执行 git mergegit rebase 命令,或者使用 git pull 命令。例:删除远程 dev分支后,使用此命令,本地的远程分支也会被清理。

git fetch 命令用于将远程仓库中的最新提交记录拉取到本地仓库中,但是不会自动合并(merge)这些提交;不会删除本地不存在的远程分支,可能会导致本地分支列表过长,不便于管理。

删除远程分支

zsh
git branch / git branch -r 	     #列出所有本地/远程分支
+git branch -D 分支名              #删除本地库分支
+git push origin --delete 分支名   #删除远程库分支
git branch / git branch -r 	     #列出所有本地/远程分支
+git branch -D 分支名              #删除本地库分支
+git push origin --delete 分支名   #删除远程库分支

删除Tag

zsh
git tag -l                       #列出所有本地/远程tag
+git tag -D tag名                 #删除本地库tag
+git push origin --delete tag名   #删除远程库tag
+git tag -l | xargs git tag -d   #删除本地所有 tag
git tag -l                       #列出所有本地/远程tag
+git tag -D tag名                 #删除本地库tag
+git push origin --delete tag名   #删除远程库tag
+git tag -l | xargs git tag -d   #删除本地所有 tag

删除远程文件

zsh
git rm -r -n --cached 文件/文件夹名称   #预览要删除的文件列表
+git rm -r --cached 文件/文件夹名称      #确定无误后删除文件
git rm -r -n --cached 文件/文件夹名称   #预览要删除的文件列表
+git rm -r --cached 文件/文件夹名称      #确定无误后删除文件

fork后的仓库,拉取合并原仓库的更新

zsh
git remote add upstream [原仓库URL] #添加上游分支路径
+git pull upstream [分支名]  				#拉取上游分支更新并合并
git remote add upstream [原仓库URL] #添加上游分支路径
+git pull upstream [分支名]  				#拉取上游分支更新并合并

合并多次提交

zsh
git rebase -i HEAD~3        #合并最近的 3 次提交,并开启交互模式
+git rebase -i <commit_sha>  #开启交互模式
git rebase -i HEAD~3        #合并最近的 3 次提交,并开启交互模式
+git rebase -i <commit_sha>  #开启交互模式
zsh
git rebase -i 8fc6389   #填第2 次提交的 hash,则表示合并 2 之后(3和 4)的提交
git rebase -i 8fc6389   #填第2 次提交的 hash,则表示合并 2 之后(3和 4)的提交

image-20230227205854474

把需要压缩的提交 pick 改为 s,必须保留一个 pick,下一步填写合并提交信息,保存退出(:wq)完成合并

image-20230227105523929

image-20230227205916425

关联多个代码托管平台

当本地仓库项同时关联 github 和 gitee,同步更新两边代码

  1. 方法一 git remote add gitee [gitee_repo_url],需要多次推送

效果:

zsh
[branch "master"]
+	remote = origin
+	merge = refs/heads/master
+[remote "origin"]
+	url = git@github.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+[remote "gitee"]
+	url = git@gitee.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/gitee/*
[branch "master"]
+	remote = origin
+	merge = refs/heads/master
+[remote "origin"]
+	url = git@github.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+[remote "gitee"]
+	url = git@gitee.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/gitee/*
zsh
#git remote -v                                                   
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (fetch)
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (push)
+origin  git@github.com:fxzer/juejin-server-mysql.git (fetch)
+origin  git@github.com:fxzer/juejin-server-mysql.git (push)
#git remote -v                                                   
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (fetch)
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (push)
+origin  git@github.com:fxzer/juejin-server-mysql.git (fetch)
+origin  git@github.com:fxzer/juejin-server-mysql.git (push)
  1. 方法二 git remote set-url --add origin [gitee_repo_url] , 只需一次推送

效果:~

zsh
[remote "origin"]
+	url = git@github.com:fxzer/json-viewer.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+	url = git@gitee.com:fxzer/json-viewer.git
+[branch "master"]
+	remote = origin
+	merge = refs/heads/master
[remote "origin"]
+	url = git@github.com:fxzer/json-viewer.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+	url = git@gitee.com:fxzer/json-viewer.git
+[branch "master"]
+	remote = origin
+	merge = refs/heads/master
zsh
#git remote -v
+origin  git@github.com:fxzer/json-viewer.git (fetch)
+origin  git@github.com:fxzer/json-viewer.git (push)
+origin  git@gitee.com:fxzer/json-viewer.git (push)
#git remote -v
+origin  git@github.com:fxzer/json-viewer.git (fetch)
+origin  git@github.com:fxzer/json-viewer.git (push)
+origin  git@gitee.com:fxzer/json-viewer.git (push)

git remote addgit remote set-url --add区别

  • git remote add 用于添加一个新的远程仓库。该本地仓库已关联远程库,希望添加新的远程库。**运用:**fork后的仓库,需要拉取合并原仓库的更新。
  • git remote set-url --add 用于向已经存在的远程仓库中添加一个新的 URL。**运用:**同一个仓库关联 github 和 gitee 方便同时更新。
  • git remote set-url 命令会替换掉原有的链接,git remote set-url --add 命令,则是添加一个标识对应的远程库链接。

改错分支但为未提交

zsh
git stash            #暂存更改到stash
+git checkout 分支名   #切换分支
+git stash pop        #从stash中取出暂存的代码修改
git stash            #暂存更改到stash
+git checkout 分支名   #切换分支
+git stash pop        #从stash中取出暂存的代码修改

提交完未推送前,需要再次提交

  • 提交完未推送前,发现代码有的有点小问题,还需要修改再提交,但是不想新增垃圾提交信息,保持简洁。
  • 只需要修改提交的内容而不需要改变提交信息, 可以使用 --no-edit 参数来跳过编辑提交信息的步骤。
zsh
git commit --amend --no-edit # 做的修改合并到最近的提交中,相当于是在原有的提交上进行修改,而不是创建一个新的提交。
+
+# 使用后在拉取代码会出现:位于分支 master
+# 您的分支和 'origin/master' 出现了偏离,
+# 并且分别有 1 和 1 处不同的提交。
+#   (使用 "git pull" 来合并远程分支)
+ git config pull.rebase true   # git pull前,需要执行此命令进行变基
git commit --amend --no-edit # 做的修改合并到最近的提交中,相当于是在原有的提交上进行修改,而不是创建一个新的提交。
+
+# 使用后在拉取代码会出现:位于分支 master
+# 您的分支和 'origin/master' 出现了偏离,
+# 并且分别有 1 和 1 处不同的提交。
+#   (使用 "git pull" 来合并远程分支)
+ git config pull.rebase true   # git pull前,需要执行此命令进行变基

修改第一次提交信息

zsh
git rebase -i --root  #把第一次提交的 pick 改为 edit 后 e
+git rebase --continue
+git rebase pull.rebase true
+git pull
+git push
git rebase -i --root  #把第一次提交的 pick 改为 edit 后 e
+git rebase --continue
+git rebase pull.rebase true
+git pull
+git push

代码提交到了错误的分支

方法一

切换到正确的分支并使用, 将指定的提交复制到当前分支,并将其添加到暂存区

zsh
git cherry-pick [commit]
git cherry-pick [commit]

方法二

使用 git rebase 命令将提交移动到正确的分支上:

  1. 切换到错误分支上:git checkout [error-branch]
  2. 将错误分支上的提交移动到正确分支上:git rebase [correct-branch]
  3. 解决冲突(如果有)
  4. 将更改提交到正确的分支上:git checkout [correct-branch],然后 git merge [error-branch]
  5. 在错误分支git push -f更新远程代码

Git 提交规范化

  • husky: Git 钩子工具,在 Git 提交过程的不同阶段自动运行脚本,以此来实现对代码的验证、格式化、测试等操作
  • @commitlint/cli: 提交信息校验脚手架
  • @commitlint/config-conventional: 定义了 commitlint 默认使用的规范。
  • commitizen: 交互式提交工具
  • conventional-changelog: 规范提交信息、并自动生成变更日志
  • cz-conventional-changelog: git cz 提交规范和 changelog 生成工具

husky 文档

zsh
# 安装
+pnpm dlx husky-init && pnpm install
+# 初始化husky配置,在根目录新增.husky配置文件。初始化配置pre-commit
+
+# 新增一个提交git commit 执行前的钩子(commit-msg)
+npx husky add .husky/commit-msg
# 安装
+pnpm dlx husky-init && pnpm install
+# 初始化husky配置,在根目录新增.husky配置文件。初始化配置pre-commit
+
+# 新增一个提交git commit 执行前的钩子(commit-msg)
+npx husky add .husky/commit-msg

注意:需要 git init后才能初始化,否则报错如下

2023-06-27-20-25-35

@commitlint/cli与@commitlint/config-conventional

zsh
#安装校验脚手架、校验规范
+pnpm i @commitlint/cli @commitlint/config-conventional -D
+
+#添加安装脚本呢
+pnpm set-script '"prepare": "husky install"'
#安装校验脚手架、校验规范
+pnpm i @commitlint/cli @commitlint/config-conventional -D
+
+#添加安装脚本呢
+pnpm set-script '"prepare": "husky install"'
js
//commitlint.config.js (若报错 type:'module')可改:commitlint.config.js ==> commitlint.config.cjs
+module.exports = {
+  extends: ["@commitlint/config-conventional"],
+};
//commitlint.config.js (若报错 type:'module')可改:commitlint.config.js ==> commitlint.config.cjs
+module.exports = {
+  extends: ["@commitlint/config-conventional"],
+};

commitizen

zsh
#全局安装
+npm install -g commitizen
#全局安装
+npm install -g commitizen

cz-conventional-changelog

zsh
#全局安装
+npm install -g cz-conventional-changelog
#全局安装
+npm install -g cz-conventional-changelog

配置 ~/.czrc, 将其设置为 commitizen 的插件。

zsh
{
+  "path": "cz-conventional-changelog"
+}
{
+  "path": "cz-conventional-changelog"
+}

作用:提交代码并生成变更日志

使用 commitizen 提交代码时,会自动启动 cz-conventional-changelog 插件,

并根据 conventional-commit 规范提示用户输入提交信息。

输入完毕后,会自动将提交信息转换成符合规范的格式,并将其写入到 CHANGELOG.md 文件中。

+ + + + \ No newline at end of file diff --git "a/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.html" "b/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.html" new file mode 100644 index 00000000..f861a346 --- /dev/null +++ "b/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.html" @@ -0,0 +1,59 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

安装Oh My Posh

可以先去Microsofe Store 安装winget,会比较方便

bash
winget install JanDeDobbeleer.OhMyPosh
winget install JanDeDobbeleer.OhMyPosh

安装完:

会在C:\Users\自己用户名\AppData\Local\Programs\oh-my-posh\themes>有很多主题

预览所有主题命令

bash
Get-PoshThemes
Get-PoshThemes

image-20220426123111651

初始化并应用主题

bash
oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes\schema.json" | Invoke-Expression
+#schema.json ---- 选择themes目录下的一款主题文件
oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes\schema.json" | Invoke-Expression
+#schema.json ---- 选择themes目录下的一款主题文件

分隔符乱码问题

但会发现分隔符会有乱码的问题

乱码问题解决方式:

安装Nerd Fonts字体,在Terminal>Power Shell选择自己安装的字体,保存重启就生效啦。

PS:刚开始以为没有我常用的JetBrain Mono字体,就没在意这种解决方案,没想到里面字体挺丰富.

配置PowerShell

因为应用的主题只在当前窗口有效果,所以需要配置每次PowerShell启动时都会执行应用主题的脚本

1.打开配置文件方式一

  • 获取到PowerShell配置文件绝对路径
bash
$PROFILE
$PROFILE

image-20220426124525580

  • 找到这个文件位置,打开并添加需要Power Shell启动时执行的脚本,保存文件重新打开Terminal看效果
bash
oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes\schema.json" | Invoke-Expression
oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes\schema.json" | Invoke-Expression

2.打开配置文件方式二

如果安装了VS Code,如下命令可以直接打开Power Shell配置文件

bash
code $PROFILE
code $PROFILE

自定义主题

可借鉴的up主题文件:https://gitee.com/NilTor/public/blob/master/oh-my-posh-config.json

更多配置可查看官网配置文档

VS Code终端配置

没有配置打开VS Code终端报错:

bash
The term 'oh-my-posh' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify
+     | that the path is correct and try again.
The term 'oh-my-posh' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify
+     | that the path is correct and try again.
  • 在环境变量新增Oh My Posh路径下bin目录

image-20220426141214178

  • 在设置中配置配置自己安装的Nerd Font终端字体,(这里我填上我安装的是JetBrainsMono Nerd Font Mono)

image-20220426141358102

隐藏提示语

每次打开都会有这四句提示语,想要打开是干干净净的界面。

image-20220426233405476

在PowerShell配置项中添加一个配置 ,配置参数 -NoLogo为隐藏提示语

json
 "commandline": "自己的pwsh.exe的路径 -NoLogo",
 "commandline": "自己的pwsh.exe的路径 -NoLogo",

完整配置参考

json
{
+    "colorScheme": "Campbell",
+    "font": 
+    {
+        "face": "JetBrainsMono Nerd Font Mono"
+    },
+    "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
+    "hidden": false,
+    "name": "PowerShell",
+    "source": "Windows.Terminal.PowershellCore",
+    "commandline": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.2.2.0_x64__8wekyb3d8bbwe\\pwsh.exe -NoLogo",
+    "startingDirectory": null
+}
{
+    "colorScheme": "Campbell",
+    "font": 
+    {
+        "face": "JetBrainsMono Nerd Font Mono"
+    },
+    "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
+    "hidden": false,
+    "name": "PowerShell",
+    "source": "Windows.Terminal.PowershellCore",
+    "commandline": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.2.2.0_x64__8wekyb3d8bbwe\\pwsh.exe -NoLogo",
+    "startingDirectory": null
+}

image-20220426233614912

+ + + + \ No newline at end of file diff --git "a/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.html" "b/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.html" new file mode 100644 index 00000000..c2b1eadd --- /dev/null +++ "b/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.html" @@ -0,0 +1,67 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

1.生成公钥和私钥

bash
ssh-keygen -t rsa -C '8888888@qq.com'  #换成自己邮箱,可以随便填,相当于一个标识
+#密码不用填 直接回车
ssh-keygen -t rsa -C '8888888@qq.com'  #换成自己邮箱,可以随便填,相当于一个标识
+#密码不用填 直接回车

image-20220416211353115

ls 查看生成的文件

image-20220416211808297

2.在代码托管平台设置添加公钥

  • 查看生成的公钥.pub文件 例如: cat id_rsa_github_gmail.pub
  • 复制公钥所有内容 ,在github/gitee/gitlab添加

image-20220416212417100

3.添加私钥到ssh-agent中

添加私钥到ssh-agent中 ,出现Identity added表示成功

bash
ssh-add ~/.ssh/id_rsa_github_qq
ssh-add ~/.ssh/id_rsa_github_qq
  1. 若提示 Could not open a connection to your authentication agent

​ 先执行ssh-agent bash 再执行上面代码

  1. 报错: Error connecting to agent: No such file or directory

​ 解决方法:检查文件是否存在,并【以管理员身份运行】在 PowerShell 执行

bash
Set-Service ssh-agent -StartupType Manual
+Start-Service ssh-agent
Set-Service ssh-agent -StartupType Manual
+Start-Service ssh-agent
  1. 报错 unable to start ssh-agent service, error :1058

​ 以【管理员身份】打开终端,执行Set-Service -Name ssh-agent -StartupType automatic

  • 查看私钥列表
bash
ssh-add -l
ssh-add -l

出现此提示表示未配置成功,重新检查步骤配置

bash
git@github.com: Permission denied (publickey).
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
git@github.com: Permission denied (publickey).
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.

4.创建config件,打开编辑

注意:文件名就是config,没有文件后缀,编辑完保存前记得去掉注释

bash
Host github.com #github主机地址
+HostName github.com #github主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_github #私钥地址
+
+Host gitlab.xxx.cn  #公司gitlab主机地址
+HostName gitlab.xxx.cn	#gitlab主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_gitlab	#私钥地址
Host github.com #github主机地址
+HostName github.com #github主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_github #私钥地址
+
+Host gitlab.xxx.cn  #公司gitlab主机地址
+HostName gitlab.xxx.cn	#gitlab主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_gitlab	#私钥地址
  • 测试连接是否成功,显示出这句话表示成功啦,可以看到自己账户名

    Hi CoderFXJ! You've successfully authenticated, but GitHub does not provide shell access.

    bash
    ssh -T git@gitee.com
    +#或
    +ssh -T git@github.com
    +
    +ssh -T git@gitlab.xxx.cn
    ssh -T git@gitee.com
    +#或
    +ssh -T git@github.com
    +
    +ssh -T git@gitlab.xxx.cn

SSH公钥私钥加密解密原理

+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/async\344\270\216await.html" "b/FrontEnd/JavaScript/async\344\270\216await.html" new file mode 100644 index 00000000..c4f84e62 --- /dev/null +++ "b/FrontEnd/JavaScript/async\344\270\216await.html" @@ -0,0 +1,227 @@ + + + + + + Javascript实现异步 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Javascript实现异步

INFO

Javascript是单线程执行语言

方式一:回调函数

js
let timer = setTimeout(()=>{
+    console.log("3秒后打印的")
+},3000)
+console.log("比setTimeout回调函数先执行")
+//本身会立刻返回,然后执行后面同步代码,回调函数则等预定时间才执行
let timer = setTimeout(()=>{
+    console.log("3秒后打印的")
+},3000)
+console.log("比setTimeout回调函数先执行")
+//本身会立刻返回,然后执行后面同步代码,回调函数则等预定时间才执行

缺点:容易形成回调地狱

js
setTimeout(()=>{
+    console.log("3秒后打印的")
+    
+   setTimeout(()=>{    
+       console.log("6秒后打印的")
+       
+         setTimeout(
+            ()=>{    
+               console.log("9秒后打印的")
+         },3000)
+   },3000)
+},3000)
setTimeout(()=>{
+    console.log("3秒后打印的")
+    
+   setTimeout(()=>{    
+       console.log("6秒后打印的")
+       
+         setTimeout(
+            ()=>{    
+               console.log("9秒后打印的")
+         },3000)
+   },3000)
+},3000)

方式二:Promise

声名Promise

new Promise(function(resolve, reject){ })

js
new Promise(function(resolve, reject) { 
+    resolve('success')  // 成功执行
+}).then(result => {
+    alert(result)  //走then
+}).finally(()=>{
+	//无论成功失败,都会执行的回调
+    //做一些清理工作,如关闭加载动画
+})
+
+new Promise(function(resolve, reject) { 
+    reject('fail')  // 失败执行
+}).then(result => {
+    alert(result)
+}).catch(error => {
+     alert(error)  //走catch
+})
new Promise(function(resolve, reject) { 
+    resolve('success')  // 成功执行
+}).then(result => {
+    alert(result)  //走then
+}).finally(()=>{
+	//无论成功失败,都会执行的回调
+    //做一些清理工作,如关闭加载动画
+})
+
+new Promise(function(resolve, reject) { 
+    reject('fail')  // 失败执行
+}).then(result => {
+    alert(result)
+}).catch(error => {
+     alert(error)  //走catch
+})

如果想终止在某个执行链的位置,可以用Promise.reject(new Error())

js
new Promise(function(resolve, reject) {
+    resolve(1)
+}).then(result => {
+    return result + 1
+}).then(result => {
+    return result + 1
+}).then(result => {
+    
+  return  Promise.reject(new Error(result + '失败'))
+   // return result + 1
+}).then(result => {
+    return result + 1
+}).catch(error => {	
+    alert(error)
+})
new Promise(function(resolve, reject) {
+    resolve(1)
+}).then(result => {
+    return result + 1
+}).then(result => {
+    return result + 1
+}).then(result => {
+    
+  return  Promise.reject(new Error(result + '失败'))
+   // return result + 1
+}).then(result => {
+    return result + 1
+}).catch(error => {	
+    alert(error)
+})

语法糖:async /await

await 表示强制等待的意思,await关键字的后面要跟一个promise对象,它总是等到该promise对象resolve成功之后执行,并且会返回resolve的结果

async标记该函数就是一个异步函数,不会阻塞其他执行逻辑的执行,被async标记的函数返回也是promise对象

async 和 await必须成对出现,不能用在普通函数上

js
async fn1() {
+ const result = await new Promise(function(resolve){  
+    setTimeout(function(){
+      resolve('fn1执行结果')
+    },5000)
+ })
+ console.log(result)
+},
+    
+fn2(){
+  this.fn1() //async的函数并不会阻塞后续同步代码执行
+  console.log('fn2执行') //先执行
+}
async fn1() {
+ const result = await new Promise(function(resolve){  
+    setTimeout(function(){
+      resolve('fn1执行结果')
+    },5000)
+ })
+ console.log(result)
+},
+    
+fn2(){
+  this.fn1() //async的函数并不会阻塞后续同步代码执行
+  console.log('fn2执行') //先执行
+}

实现fn1先执行

js
 async fn2(){
+     await this.fn1()
+     console.log('fn2执行')
+   }
 async fn2(){
+     await this.fn1()
+     console.log('fn2执行')
+   }

捕获异常

js
   async  getCatch () {
+      try { // 通过 try/catch捕获异常
+        await new Promise(function (resolve, reject) {
+          reject(new Error('失败'))
+        })
+         console.log('log1')
+      } catch (error) {
+         console.log('log2')
+      }
+   }
   async  getCatch () {
+      try { // 通过 try/catch捕获异常
+        await new Promise(function (resolve, reject) {
+          reject(new Error('失败'))
+        })
+         console.log('log1')
+      } catch (error) {
+         console.log('log2')
+      }
+   }

使用陷阱

1.会打破异步操作并行

js
async  fn1(){
+    const a = await fetch("http://.../post/1")
+    const b = await fetch("http://.../post/2")
+    //a任务需要等到b任务执行完后才执行
+}
async  fn1(){
+    const a = await fetch("http://.../post/1")
+    const b = await fetch("http://.../post/2")
+    //a任务需要等到b任务执行完后才执行
+}

高效做法

js
async  fn1(){
+    const promistA =  fetch("http://.../post/1")
+    const promistB =  fetch("http://.../post/2")
+    //利用 Promise.all组合
+    const [a,b] = await Promise.all([promiseA,pormiseB])
+    
+}
async  fn1(){
+    const promistA =  fetch("http://.../post/1")
+    const promistB =  fetch("http://.../post/2")
+    //利用 Promise.all组合
+    const [a,b] = await Promise.all([promiseA,pormiseB])
+    
+}

2.循环中执行异步操作,不能直接使用forEach,map等方法

js
async  fn(){
+    [1,2,3].forEach(await (item)=>{
+        await someAsyncOpt()
+    })//会立刻返回,并不会等待所有异步操作执行完
+    console.log('done')
+}
async  fn(){
+    [1,2,3].forEach(await (item)=>{
+        await someAsyncOpt()
+    })//会立刻返回,并不会等待所有异步操作执行完
+    console.log('done')
+}

解决方法

js
async  fn(){
+   for(let i of  [1,2,3]){
+		await someAsyncOpt()
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}
async  fn(){
+   for(let i of  [1,2,3]){
+		await someAsyncOpt()
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}

高效做法

js
async  fn(){
+    const promises = [
+        someAsyncOpt(),
+        someAsyncOpt(),
+        someAsyncOpt(),
+    ]
+   for await (let res of promises ){
+		//...
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}
async  fn(){
+    const promises = [
+        someAsyncOpt(),
+        someAsyncOpt(),
+        someAsyncOpt(),
+    ]
+   for await (let res of promises ){
+		//...
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.html" "b/FrontEnd/JavaScript/\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.html" new file mode 100644 index 00000000..e9277c65 --- /dev/null +++ "b/FrontEnd/JavaScript/\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.html" @@ -0,0 +1,147 @@ + + + + + + if else 多分支优化 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

if else 多分支优化

简单分支

js
//优化前
+function speak(name){
+  if(name==='老牛'){
+    console.log('老牛哞哞叫')
+  }else if(name==='老虎'){
+    console.log('老牛嗷嗷叫')
+  }else if(name==='老鸡'){
+    console.log('老牛咯咯叫')
+  }
+}
+
+//优化后
+function speak(name){
+   const map = {
+    老牛:'老牛哞哞叫',
+    老虎:'老虎嗷嗷叫',
+    老鸡:'老鸡咯咯叫'
+   }
+  if(map[name]){
+    console.log(map[name])
+  }else {
+    console.log('不知道怎么叫')
+  }
+}
+
+speak('老牛')
//优化前
+function speak(name){
+  if(name==='老牛'){
+    console.log('老牛哞哞叫')
+  }else if(name==='老虎'){
+    console.log('老牛嗷嗷叫')
+  }else if(name==='老鸡'){
+    console.log('老牛咯咯叫')
+  }
+}
+
+//优化后
+function speak(name){
+   const map = {
+    老牛:'老牛哞哞叫',
+    老虎:'老虎嗷嗷叫',
+    老鸡:'老鸡咯咯叫'
+   }
+  if(map[name]){
+    console.log(map[name])
+  }else {
+    console.log('不知道怎么叫')
+  }
+}
+
+speak('老牛')

条件单一,处理不同

js
function speak(name){
+   const map = {
+    老牛:() =>  { ... },
+    老虎:() =>  { ... },
+    老鸡:() =>  { ... }
+   }
+  if(map[name]){
+     map[name]()
+  }else {
+    console.log('xxx')
+  }
+}
function speak(name){
+   const map = {
+    老牛:() =>  { ... },
+    老虎:() =>  { ... },
+    老鸡:() =>  { ... }
+   }
+  if(map[name]){
+     map[name]()
+  }else {
+    console.log('xxx')
+  }
+}

条件复杂,处理也复杂

js
function speak(name){
+   const arr = [  //条件,处理映射
+    [
+      () =>  { ... },//条件1
+      () =>  { ... } //处理函数1
+    ],
+    [
+      () =>  { ... },//条件2
+      () =>  { ... } //处理函数2
+    ],
+    [
+      () =>  { ... },//条件3
+      () =>  { ... } //处理函数4
+    ],
+   ]
+
+  const target = arr.find(item => item[0]())
+  if(target){
+     target[1]()
+  }else {
+    console.log('xxx')
+  }
+}
function speak(name){
+   const arr = [  //条件,处理映射
+    [
+      () =>  { ... },//条件1
+      () =>  { ... } //处理函数1
+    ],
+    [
+      () =>  { ... },//条件2
+      () =>  { ... } //处理函数2
+    ],
+    [
+      () =>  { ... },//条件3
+      () =>  { ... } //处理函数4
+    ],
+   ]
+
+  const target = arr.find(item => item[0]())
+  if(target){
+     target[1]()
+  }else {
+    console.log('xxx')
+  }
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.html" "b/FrontEnd/JavaScript/\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.html" new file mode 100644 index 00000000..c4879a65 --- /dev/null +++ "b/FrontEnd/JavaScript/\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.html" @@ -0,0 +1,81 @@ + + + + + + JS 图片懒加载 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

JS 图片懒加载

方案一:监听滚动

TIP

监听图片顶部到达视口底部,把自定义属性 data-src赋值给src

js
const images = document.querySelectorAll('img')
+window.addEventListener('scroll', (e) => {
+    images.forEach(
+        image => {
+            const imageTop = image.getBoundingClientRect().top
+            if (imageTop < window.innerHeight) {
+                const data_src = image.getAttribute('data-src')
+                image.setAttribute('src', data_src)
+            }
+        }
+    )
+})
const images = document.querySelectorAll('img')
+window.addEventListener('scroll', (e) => {
+    images.forEach(
+        image => {
+            const imageTop = image.getBoundingClientRect().top
+            if (imageTop < window.innerHeight) {
+                const data_src = image.getAttribute('data-src')
+                image.setAttribute('src', data_src)
+            }
+        }
+    )
+})

方案二:观察者

js
const images = document.querySelectorAll('img')
+const callback = enteries => {
+    enteries.forEach(entry => {
+        if (entry.isIntersecting) {
+            const img = entry.target
+            const data_src = img.getAttribute('data-src')
+            img.setAttribute('src', data_src)
+            observer.unobserve(img)
+        }
+    });
+}
+const observer = new IntersectionObserver(callback)
+images.forEach(image => {
+    observer.observe(image)
+})
const images = document.querySelectorAll('img')
+const callback = enteries => {
+    enteries.forEach(entry => {
+        if (entry.isIntersecting) {
+            const img = entry.target
+            const data_src = img.getAttribute('data-src')
+            img.setAttribute('src', data_src)
+            observer.unobserve(img)
+        }
+    });
+}
+const observer = new IntersectionObserver(callback)
+images.forEach(image => {
+    observer.observe(image)
+})
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.html" "b/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.html" new file mode 100644 index 00000000..09027d2d --- /dev/null +++ "b/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.html" @@ -0,0 +1,143 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

1.算术运算符

隐式类型转换

除了加法和其他字符串运算时,它先将其他值转为字符串,在进行拼接;其他运算它先将其他值转为数字,在进行运算

js
a = 10 - '5' //5
+a = 10 - true // 9
+a = 10 - false //10
+a = 10 - undefined // NaN
+a = 10 - null // 10
a = 10 - '5' //5
+a = 10 - true // 9
+a = 10 - false //10
+a = 10 - undefined // NaN
+a = 10 - null // 10

2.赋值运算符

js
let a = 10
+a = a + 10 // a += 10  (*= 	/=   %=		**=)
+//	??= 只有当a为undefined或null才会进行赋值
let a = 10
+a = a + 10 // a += 10  (*= 	/=   %=		**=)
+//	??= 只有当a为undefined或null才会进行赋值

3..运算符

js
+'123' // 123
+a = 123
+b = -a //-123
+'123' // 123
+a = 123
+b = -a //-123

4.自增和自减

js
//	++ 使用后回事原来的变量立刻增加1
+a++
+a--
+
+//前自增:返回自增前的值
+//后自增:返回自增后的值
//	++ 使用后回事原来的变量立刻增加1
+a++
+a--
+
+//前自增:返回自增前的值
+//后自增:返回自增后的值

5.逻辑运算符

js
!   //逻辑非:对布尔值值取反,对非布尔值值取反,会先将其转为布尔值值再取反,可运用于隐式转布尔值   !!123 -> true
+    
+&&  //逻辑与:左右都为true返回true,否则返回false;非布尔值运算,会先转为布尔值后运算,但是最终返回原值
+    	//-	第一个值为(falsy),则直接返回第一个值的原值1,如果第一个值为ture,则直接返回第二个值
+    	NaN && 2	-> NaN
+		0 && 1 		-> 0
+
+        1 && undefined	->	undefined
+        1 && false 		->	false
+
+||  //逻辑或:左右有true,则不看第二个值,则返回true的原值,否则返回false 	
+      	12 || false		->	 12	
+		null || {a : 1}	->	 {a : 1}
!   //逻辑非:对布尔值值取反,对非布尔值值取反,会先将其转为布尔值值再取反,可运用于隐式转布尔值   !!123 -> true
+    
+&&  //逻辑与:左右都为true返回true,否则返回false;非布尔值运算,会先转为布尔值后运算,但是最终返回原值
+    	//-	第一个值为(falsy),则直接返回第一个值的原值1,如果第一个值为ture,则直接返回第二个值
+    	NaN && 2	-> NaN
+		0 && 1 		-> 0
+
+        1 && undefined	->	undefined
+        1 && false 		->	false
+
+||  //逻辑或:左右有true,则不看第二个值,则返回true的原值,否则返回false 	
+      	12 || false		->	 12	
+		null || {a : 1}	->	 {a : 1}

6.关系运算符

js
//用来检查两个值的关系是否成立,成立返回true,否则返回false (多个比较用&&)
+	>	>=	<	<=
+// 非数值与数值比较会先非数值转为数值再比较  7 < '10' ->  true
+//	两端为字符串则逐个比较字符的Unicode编码	 
+   'a' > 'b' -> false		
+   'abc' < 'b' -> true(比完第一位则结束)
+   '12' < '2'	-> true
//用来检查两个值的关系是否成立,成立返回true,否则返回false (多个比较用&&)
+	>	>=	<	<=
+// 非数值与数值比较会先非数值转为数值再比较  7 < '10' ->  true
+//	两端为字符串则逐个比较字符的Unicode编码	 
+   'a' > 'b' -> false		
+   'abc' < 'b' -> true(比完第一位则结束)
+   '12' < '2'	-> true

7.相等运算符

js
==/!=	//用来比较两个值是否相等/不相等,不同类型会转为相同类型再比较	
+    '2' == 2	-> true
+	//null和undefined进行相等比较会返回true(null == undefined -> true)
+	//NaN不和任何值相等,包括它自身
+===/!== //检查两个值是否全等/不全等,不会自动类型转换
+    '2' == 2	-> false
+	//null === undefined -> false
==/!=	//用来比较两个值是否相等/不相等,不同类型会转为相同类型再比较	
+    '2' == 2	-> true
+	//null和undefined进行相等比较会返回true(null == undefined -> true)
+	//NaN不和任何值相等,包括它自身
+===/!== //检查两个值是否全等/不全等,不会自动类型转换
+    '2' == 2	-> false
+	//null === undefined -> false

8.条件运算符

js
表达式 ? 表达式1 : 表达式2	//let max = a > b ? a : b
表达式 ? 表达式1 : 表达式2	//let max = a > b ? a : b

9.控制语句

js
if{	}else if(){	}else{	}
+if //不加{}if只会控制紧随其后的一条语句
+ 
+switch(表达式){
+    case 表达式:
+        break
+        ...
+    default
+        ...
+        //表达式进行全等比较,满足则执行代码,否则比较其他case后的表达式
+}
if{	}else if(){	}else{	}
+if //不加{}if只会控制紧随其后的一条语句
+ 
+switch(表达式){
+    case 表达式:
+        break
+        ...
+    default
+        ...
+        //表达式进行全等比较,满足则执行代码,否则比较其他case后的表达式
+}

10.循环语句

js
//循环三要素 1.初始化变量	2.条件表达式	3.更新表达式
+while(条件表达式){...}
+do{	...	}while(表达式)	//先执行一次循环体,再判断条件是否执行循环体
+for(let i = 0;i < 10;i++){ ... } //for(;;)死循环
//循环三要素 1.初始化变量	2.条件表达式	3.更新表达式
+while(条件表达式){...}
+do{	...	}while(表达式)	//先执行一次循环体,再判断条件是否执行循环体
+for(let i = 0;i < 10;i++){ ... } //for(;;)死循环

break与continue💔终止离它最近的循环, break立即循环停止; continue跳过当前循环,继续下一次循环

11.数据类型

js
//原始值(7种):
+	Number,String,Boolean,Null,Undefined,BigInt,Symbol
+//引用值(对象)
+	Object
+    {
+        [Symbol()]:'此值不可枚举'
+    }
//原始值(7种):
+	Number,String,Boolean,Null,Undefined,BigInt,Symbol
+//引用值(对象)
+	Object
+    {
+        [Symbol()]:'此值不可枚举'
+    }
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.html" "b/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.html" new file mode 100644 index 00000000..ce705893 --- /dev/null +++ "b/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.html" @@ -0,0 +1,445 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

this指向

根据函数调用方式的不同,this的值也不同:

TIP

  1. 以函数形式调用,this是window
  2. 以方法形式调用, this是调用方法的对象
  3. 构造函数中,this是新建的对象
  4. 箭头函数没有自己的this, 由外层作用域决定
  5. 通过call和apply调用的函数,它们的第一个参数就是函数的this
  6. 通过bind返回的函数,this由bind第一个参数决定(无法修改)
js
function fn(){
+	console.log(this)//window
+}
+let obj = {
+	name:'zhansan',
+    fn(){
+		console.log(this)//obj
+        function fn2(){
+            console.log(this) //window     
+        }
+        fn3 = ()=> {
+            console.log(this)//obj,与调用方式无关,指向声明时外层作用域的this
+        }
+        fn2()//以函数形式调用指向window
+    }
+}
+obj.fn()//以方法形式调用,指向obj
function fn(){
+	console.log(this)//window
+}
+let obj = {
+	name:'zhansan',
+    fn(){
+		console.log(this)//obj
+        function fn2(){
+            console.log(this) //window     
+        }
+        fn3 = ()=> {
+            console.log(this)//obj,与调用方式无关,指向声明时外层作用域的this
+        }
+        fn2()//以函数形式调用指向window
+    }
+}
+obj.fn()//以方法形式调用,指向obj

函数三种调用方式

js
fn()
+fn.call()
+fn.apply()
fn()
+fn.call()
+fn.apply()

call和bind与apply

  1. call 和 apply除了可以调用函数,还可以用来指定函数中的this

    • 通过call方法调用函数,函数的实参直接在第一个参数后一个一个的列出来
    • apply 实参需要通过一个数组传递
  2. bind() 是函数的方法,可以用来创建一个新的函数

    • bind可以为新函数绑定this
    • bind可以为新函数绑定参数
js
fn2.call(obj, "hello", true)//会立即执行
+fn2.apply(obj, ["hello", true]//会立即执行
+let newfn = fn.bind(obj, 10, 20, 30)//不会立即执行, 返回一个新函数 	newfn()
fn2.call(obj, "hello", true)//会立即执行
+fn2.apply(obj, ["hello", true]//会立即执行
+let newfn = fn.bind(obj, 10, 20, 30)//不会立即执行, 返回一个新函数 	newfn()

箭头函数没有自身的this,它的this由定义时外层作用域决定,

  • 也无法通过call apply 和 bind修改它的this

  • 箭头函数中没有arguments

可变参数 arguments

js
 // 定义一个函数,可以求任意个数值的和
+function sum() {
+// 通过arguments,可以不受参数数量的限制更加灵活的创建函数
+ /* arguments
+    - arguments是函数中又一个隐含参数
+    - arguments是一个类数组对象(伪数组)
+        和数组相似,可以通过索引来读取元素,也可以通过for循环变量,							
+        但是它不是一个数组对象,不能调用数组的方法
+    - arguments用来存储函数的实参,
+        无论用户是否定义形参,实参都会存储到arguments对象中
+        可以通过该对象直接访问实参*/
+    let result = 0
+
+    for (let num of arguments) {
+        result += num
+    }
+
+    return result
+}
 // 定义一个函数,可以求任意个数值的和
+function sum() {
+// 通过arguments,可以不受参数数量的限制更加灵活的创建函数
+ /* arguments
+    - arguments是函数中又一个隐含参数
+    - arguments是一个类数组对象(伪数组)
+        和数组相似,可以通过索引来读取元素,也可以通过for循环变量,							
+        但是它不是一个数组对象,不能调用数组的方法
+    - arguments用来存储函数的实参,
+        无论用户是否定义形参,实参都会存储到arguments对象中
+        可以通过该对象直接访问实参*/
+    let result = 0
+
+    for (let num of arguments) {
+        result += num
+    }
+
+    return result
+}

剩余参数 ...args

js
 function sum2(...num) {
+ /* 
+剩余参数,在定义函数时可以将参数指定为剩余参数
+- 剩余参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
+- 作用和arguments基本是一致,但是也具有一些不同点:
+    是一个数组,名字可以自己指定,配合其他参数一起使用,剩余参数写到最后。
+ */
+    return num.reduce((a, b) => a + b, 0)
+ }
+function fn3(a, b, ...args) {
+  console.log(args)
+ }
 function sum2(...num) {
+ /* 
+剩余参数,在定义函数时可以将参数指定为剩余参数
+- 剩余参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
+- 作用和arguments基本是一致,但是也具有一些不同点:
+    是一个数组,名字可以自己指定,配合其他参数一起使用,剩余参数写到最后。
+ */
+    return num.reduce((a, b) => a + b, 0)
+ }
+function fn3(a, b, ...args) {
+  console.log(args)
+ }

Map

  • Map用来存储键值对结构的数据(key-value)
  • Object中存储的数据就可以认为是一种键值对结构
  • Map和Object的主要区别:
    • Object中的属性名只能是字符串或符号,如果传递了一个其他类型的属性名, JS解释器会自动将其转换为字符串
    • Map中任何类型的值都可以称为数据的key
js
/*属性和方法:
+  map.size() 获取map中键值对的数量
+  map.set(key, value) 向map中添加键值对
+  map.get(key) 根据key获取值   
+  map.delete(key) 删除指定数据
+  map.has(key) 检查map中是否包含指定键
+  map.clear() 删除全部的键值对*/
+    
+    const obj = {
+        "name":"孙悟空",
+        'age':18,
+        [Symbol()]:"哈哈",
+        [obj2]:"嘻嘻"
+    }
/*属性和方法:
+  map.size() 获取map中键值对的数量
+  map.set(key, value) 向map中添加键值对
+  map.get(key) 根据key获取值   
+  map.delete(key) 删除指定数据
+  map.has(key) 检查map中是否包含指定键
+  map.clear() 删除全部的键值对*/
+    
+    const obj = {
+        "name":"孙悟空",
+        'age':18,
+        [Symbol()]:"哈哈",
+        [obj2]:"嘻嘻"
+    }

将map转换为数组

js
const arr = Array.from(map)//const arr = [...map]
+ // 遍历map
+  for (const [key, value] of map) {
+     const [key, value] = entry
+    console.log(key, value)
+   }
+
+    map.forEach((key, value)=>{
+        console.log(key, value)
+    })
+
+ map.keys() - 获取map的所有的key
+ map.values() - 获取map的所有的value
const arr = Array.from(map)//const arr = [...map]
+ // 遍历map
+  for (const [key, value] of map) {
+     const [key, value] = entry
+    console.log(key, value)
+   }
+
+    map.forEach((key, value)=>{
+        console.log(key, value)
+    })
+
+ map.keys() - 获取map的所有的key
+ map.values() - 获取map的所有的value

数组转map

js
const map2 = new Map([
+    ["name", "猪八戒"],
+    ["age", 18],
+    [{}, () => {}],
+])
const map2 = new Map([
+    ["name", "猪八戒"],
+    ["age", 18],
+    [{}, () => {}],
+])

Set

js
/* - 使用方式:
+    创建
+        - new Set()
+        - new Set([...])
+
+    方法
+        size 获取数量
+        add() 添加元素
+        has() 检查元素
+        delete() 删除元素
+        [...set]转为数组获取元素 
+        set.entries() 得到键值对(键值对一样)
+        */
/* - 使用方式:
+    创建
+        - new Set()
+        - new Set([...])
+
+    方法
+        size 获取数量
+        add() 添加元素
+        has() 检查元素
+        delete() 删除元素
+        [...set]转为数组获取元素 
+        set.entries() 得到键值对(键值对一样)
+        */

随机数生成

js
 Math.random() --> 0 - 1
+//生成 0-x之间的随机数:
+Math.round(Math.random() * x)
+Math.floor(Math.random() * (x + 1))
+
+//生成 x-y 之间的随机数
+Math.round(Math.random() * (y-x) + x)
 Math.random() --> 0 - 1
+//生成 0-x之间的随机数:
+Math.round(Math.random() * x)
+Math.floor(Math.random() * (x + 1))
+
+//生成 x-y 之间的随机数
+Math.round(Math.random() * (y-x) + x)

时间格式化

js
const d = new Date()
+
+let result = d.toLocaleDateString() // 将日期转换为本地的字符串		'2021/10/1
+result = d.toLocaleTimeString() // 将时间转换为本地的字符串 	'21:32:35'
+/*   - 参数:
+1. locales: 描述语言和国家信息的字符串
+    zh-CN 中文中国
+    zh-HK 中文香港
+    en-US 英文美国
+2. options: 需要一个对象作为参数,在对象中可以通过对象的属性来对日期的格式进行配置
+*/
+  result = d.toLocaleString("zh-CN", {
+    year: "numeric",
+    month: "long",
+    day: "2-digit",
+    weekday: "short",
+    hour: "2-digit",
+    minute: "2-digit"
+})
const d = new Date()
+
+let result = d.toLocaleDateString() // 将日期转换为本地的字符串		'2021/10/1
+result = d.toLocaleTimeString() // 将时间转换为本地的字符串 	'21:32:35'
+/*   - 参数:
+1. locales: 描述语言和国家信息的字符串
+    zh-CN 中文中国
+    zh-HK 中文香港
+    en-US 英文美国
+2. options: 需要一个对象作为参数,在对象中可以通过对象的属性来对日期的格式进行配置
+*/
+  result = d.toLocaleString("zh-CN", {
+    year: "numeric",
+    month: "long",
+    day: "2-digit",
+    weekday: "short",
+    hour: "2-digit",
+    minute: "2-digit"
+})

面向对象之类

js
 class Person{
+	 constructor(name, age, gender){
+        // console.log("构造函数执行了~", name, age, gender)
+        // 可以在构造函数中,为实例属性进行赋值
+        // 在构造函数中,this表示当前所创建的对象
+        this.name = name
+        this.age = age
+        this.gender = gender
+
+    }
+
+    // sayHello = function(){} // 添加方法的一种方式
+
+    sayHello(){
+        console.log('大家好,我是' + this.name)
+    } // 添加方法(实例方法) 实例方法中this就是当前实例
+
+    static test(){
+        console.log("我是静态方法", this)
+    } // 静态方法(类方法) 通过类来调用 静态方法中this指向的是当前类
+
+}
 class Person{
+	 constructor(name, age, gender){
+        // console.log("构造函数执行了~", name, age, gender)
+        // 可以在构造函数中,为实例属性进行赋值
+        // 在构造函数中,this表示当前所创建的对象
+        this.name = name
+        this.age = age
+        this.gender = gender
+
+    }
+
+    // sayHello = function(){} // 添加方法的一种方式
+
+    sayHello(){
+        console.log('大家好,我是' + this.name)
+    } // 添加方法(实例方法) 实例方法中this就是当前实例
+
+    static test(){
+        console.log("我是静态方法", this)
+    } // 静态方法(类方法) 通过类来调用 静态方法中this指向的是当前类
+
+}

面向对象的特点:封装、继承和多态

封装 —— 安全性 继承 —— 扩展性 多态 —— 灵活性

封装

TIP

  1. 对象就是一个用来存储不同属性的容器
  2. 对象不仅存储属性,还要负责数据的安全, 直接添加到对象中的属性,并不安全,因为它们可以被任意的修改
  3. 如何确保数据的安全:
    • 私有化数据: 将需要保护的数据设置为私有,只能在类内部使用
    • 提供setter和getter方法来开放对数据的操作
    • 属性设置私有,通过getter setter方法操作属性带来的好处
      1. 可以控制属性的读写权限
      2. 可以在方法中对属性的值进行验证
js
 - 实现封装的方式
+    1.属性私有化 #
+    2.通过getter和setter方法来操作属性
+        get 属性名(){
+            return this.#属性
+        }
+
+        set 属性名(参数){
+            this.#属性 = 参数
+        }
 - 实现封装的方式
+    1.属性私有化 #
+    2.通过getter和setter方法来操作属性
+        get 属性名(){
+            return this.#属性
+        }
+
+        set 属性名(参数){
+            this.#属性 = 参数
+        }
js
 class Person {
+	 #name//实例使用#开头就变成了私有属性,私有属性只能在类内部访问
+        constructor(name, age, gender) {
+            this.#name = name
+        }
+
+        sayHello() {
+            console.log(this.#name)
+        }
+ 
+        getName(){// getter方法,用p.getName()来读取属性
+            return this.#name
+        }
+
+        // setter方法,用来设置属性,p.setName('zhangsan')
+        setName(name){
+            this.#name = name
+        }
+
+        get name(){//简化读取方式:p.name
+            return this.#name
+        }
+
+        set name(gender){
+            this.#name = name
+        }
+    }
 class Person {
+	 #name//实例使用#开头就变成了私有属性,私有属性只能在类内部访问
+        constructor(name, age, gender) {
+            this.#name = name
+        }
+
+        sayHello() {
+            console.log(this.#name)
+        }
+ 
+        getName(){// getter方法,用p.getName()来读取属性
+            return this.#name
+        }
+
+        // setter方法,用来设置属性,p.setName('zhangsan')
+        setName(name){
+            this.#name = name
+        }
+
+        get name(){//简化读取方式:p.name
+            return this.#name
+        }
+
+        set name(gender){
+            this.#name = name
+        }
+    }

继承

继承

  • 可以通过extends关键来完成继承 时,就相当于将另一个类中的代码复制到了当前类中(简单理解)
  • 继承发生时,被继承的类称为 父类(超类),继承的类称为 子类 的代码,并且可以在不修改一个类的前提对其进行扩展
js
 class Animal{
+    constructor(name){
+        this.name = name
+    }
+    sayHello(){
+        console.log("动物在叫~")
+    }
+}
+
+class Dog extends Animal{
+    // 重写构造函数
+    constructor(name, age){
+        // 重写构造函数时,构造函数的第一行代码必须为super()
+        super(name) // 调用父类的构造函数
+        this.age = age
+
+    }
+	// 在子类中,可以通过创建同名方法来重写父类的方法
+    sayHello(){
+        console.log("汪汪汪")
+    }
+}
+const dog = new Dog("旺财")
+dog.sayHello()
 class Animal{
+    constructor(name){
+        this.name = name
+    }
+    sayHello(){
+        console.log("动物在叫~")
+    }
+}
+
+class Dog extends Animal{
+    // 重写构造函数
+    constructor(name, age){
+        // 重写构造函数时,构造函数的第一行代码必须为super()
+        super(name) // 调用父类的构造函数
+        this.age = age
+
+    }
+	// 在子类中,可以通过创建同名方法来重写父类的方法
+    sayHello(){
+        console.log("汪汪汪")
+    }
+}
+const dog = new Dog("旺财")
+dog.sayHello()

多态

在JS中不会检查参数的类型,所以这就意味着任何数据都可以作为参数传递 指定的类型,只要对象满足某些条件即可

js
function sayHello(obj){
+ console.log("Hello,"+obj.name)
+}
+//只要参数有obj.name就可以调用
+sayHello(dog)
+sayHello(person)
function sayHello(obj){
+ console.log("Hello,"+obj.name)
+}
+//只要参数有obj.name就可以调用
+sayHello(dog)
+sayHello(person)

对象的结构

原型

对象中存储属性的区域实际有两个:

TIP

  1. 对象自身

    • 直接通过对象所添加的属性,位于对象自身中
    • 中通过 x = y 的形式添加的属性,位于对象自身中
  2. 原型对象(prototype)

    • 对象中还有一些内容,会存储到其他的对象里(原型对象)
    • 在对象中会有一个属性用来存储原型对象,这个属性叫做__proto__
    • 原型对象也负责为对象存储属性,
      当我们访问对象中的属性时,会优先访问对象自身的属性,
      对象自身不包含该属性时,才会去原型对象中寻找
    • 会添加到原型对象中的情况:
      1. 在类中通过xxx(){}方式添加的方法,位于原型中
      2. 主动向原型中添加的属性或方法
  3. 访问一个对象的原型对象

    • obj.__proto__
    • Object.getPrototypeOf(对象)
  4. 原型对象中的数据:

    • 对象中的数据(属性、方法等)
    • constructor (对象的构造函数)

原型链: 原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同 obj对象的原型链:obj对象 --> 原型 --> null

原型链

原型链属性查找规则

  1. 读取对象属性时,会优先对象自身属性,
  2. 如果对象中有,则使用,没有则去对象的原型中寻找
  3. 如果原型中有,则使用,没有则去原型的原型中寻找
  4. 直到找到Object对象的原型(Object的原型没有原型(为null))
  5. 如果依然没有找到,则返回undefined

原型的作用:

  1. 原型就相当于是一个公共的区域,可以被所有该类实例访问,
  2. 可以将该类实例中,所有的公共属性(方法)统一存储到原型中
  3. 这样我们只需要创建一个属性,即可被所有实例访问
  4. 一修改就是修改所有实例的原型
  5. 无需创建实例即可完成对类的修改

修改原型

原则

  1. 原型尽量不要手动改
  2. 要改也不要通过实例对象去改
  3. 通过 类.prototype 属性去修改
  4. 最好不要直接给prototype去赋值
js
 Person.prototype.fly = () => {	//在原型添加方法
+    console.log("我在飞!")
+}
 Person.prototype.fly = () => {	//在原型添加方法
+    console.log("我在飞!")
+}

instanceof/in/hasOwn

用于检查的是对象的原型链上是否有该类 dog instanceof Animal

检查对象属性

  • in:使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true
  • 对象.hasOwnProperty(属性名):用来检查一个对象的 自身 是否含有某个属性
  • Object.hasOwn(对象, 属性名):用来检查一个对象的 自身 是否含有某个属性

10.new运算符

new运算符是创建对象时,将会发生这4件事:

  1. 创建一个普通的JS对象(Object对象 {}), 称其为新对象

  2. 将构造函数的prototype属性设置为新对象的原型

  3. 使用实参来执行构造函数,并且将新对象设置为函数中的this

  4. 如果构造函数返回的是一个非原始值,则该值会作为new运算的返回值返回

    如果构造函数的返回值是一个原始值或者没有指定返回值(undefined)

    新的对象将会作为返回值返回(通常不会为构造函数指定返回值)

js
function MyClass(){
+
+     // let newInstance = {}
+     // newInstance.__proto__ = MyClass.prototype
+     // this = newInstance
+     // return newInstance
+
+     }
function MyClass(){
+
+     // let newInstance = {}
+     // newInstance.__proto__ = MyClass.prototype
+     // this = newInstance
+     // return newInstance
+
+     }

对象的分类

  1. 内建对象: 由ES标准所定义的对象
  2. 宿主对象: 由浏览器提供的对象
  3. 自定义对象: 由开发人员自己创建的对象(Vue, React)
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\345\270\270\350\247\201\347\256\227\346\263\225.html" "b/FrontEnd/JavaScript/\345\270\270\350\247\201\347\256\227\346\263\225.html" new file mode 100644 index 00000000..518e82df --- /dev/null +++ "b/FrontEnd/JavaScript/\345\270\270\350\247\201\347\256\227\346\263\225.html" @@ -0,0 +1,1713 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

括号匹配

js
let str1 = '{[]}'	//true
+let str2 = '{[[]}'	//false
+let str3 = '{[]}['	//false
+let str4 = '{[()]}'	//true
let str1 = '{[]}'	//true
+let str2 = '{[[]}'	//false
+let str3 = '{[]}['	//false
+let str4 = '{[()]}'	//true

解决方案:

js
//方案一:
+const isValid = function(str) {
+  	if (str.length == 0) return false
+  	let arr = []
+    let map = {
+        ')': '(',
+        '}': '{',
+        ']': '['
+    }
+    for (let i = 0; i < str.length; i++) {
+        if (str[i] == '(' || str[i] == '{' || str[i] == '[') {
+            arr.push(str[i])
+        } else {
+            //栈顶出栈的左括号 !== map取出右括号匹配的括号类型
+            if (map[str[i]] != arr.pop()) {
+                return false
+            }
+        }
+    }
+    // arr数组已全部匹配,出完栈
+    if (arr.length !== 0) {
+        return false
+    }
+    return true
+}
+
+//方案二:
+function isMatched(str) {
+  let stack = [];
+  let top = -1;
+
+  for (let i = 0; i < str.length; i++) {
+    let ch = str.charAt(i);
+
+    if (ch === '{' || ch === '[' || ch === '(') {
+      stack.push(ch);
+      top++;
+    } else if (ch === '}' && stack[top] === '{') {
+      stack.pop();
+      top--;
+    } else if (ch === ']' && stack[top] === '[') {
+      stack.pop();
+      top--;
+    } else if (ch === ')' && stack[top] === '(') {
+      stack.pop();
+      top--;
+    } else {
+      return false;
+    }
+  }
+
+  return stack.length === 0;
+}
//方案一:
+const isValid = function(str) {
+  	if (str.length == 0) return false
+  	let arr = []
+    let map = {
+        ')': '(',
+        '}': '{',
+        ']': '['
+    }
+    for (let i = 0; i < str.length; i++) {
+        if (str[i] == '(' || str[i] == '{' || str[i] == '[') {
+            arr.push(str[i])
+        } else {
+            //栈顶出栈的左括号 !== map取出右括号匹配的括号类型
+            if (map[str[i]] != arr.pop()) {
+                return false
+            }
+        }
+    }
+    // arr数组已全部匹配,出完栈
+    if (arr.length !== 0) {
+        return false
+    }
+    return true
+}
+
+//方案二:
+function isMatched(str) {
+  let stack = [];
+  let top = -1;
+
+  for (let i = 0; i < str.length; i++) {
+    let ch = str.charAt(i);
+
+    if (ch === '{' || ch === '[' || ch === '(') {
+      stack.push(ch);
+      top++;
+    } else if (ch === '}' && stack[top] === '{') {
+      stack.pop();
+      top--;
+    } else if (ch === ']' && stack[top] === '[') {
+      stack.pop();
+      top--;
+    } else if (ch === ')' && stack[top] === '(') {
+      stack.pop();
+      top--;
+    } else {
+      return false;
+    }
+  }
+
+  return stack.length === 0;
+}

解析:

  • 利用栈来实现括号匹配,用 top 标识栈顶元素的下标,初始值为 -1
  • 遍历字符串中的每个字符 ch
  • 如果是左括号 {[(,则入栈。
  • 如果是右括号 }]),则判断栈顶元素是否匹配,如果匹配则出栈,否则不匹配。
  • 如果字符不是括号,则返回 false
  • 最后,如果栈为空说明所有括号都匹配,返回 true,否则不匹配返回 false

简单递归

计算阶乘

js
function factorial(n) {
+  if (n === 0) {
+    return 1;
+  }
+  return n * factorial(n - 1);
+}
function factorial(n) {
+  if (n === 0) {
+    return 1;
+  }
+  return n * factorial(n - 1);
+}
  1. 计算斐波那契数列(Fibonacci)
js
function fibonacci(n) {
+  if (n <= 1) {
+    return n;
+  }
+  return fibonacci(n - 1) + fibonacci(n - 2);
+}
function fibonacci(n) {
+  if (n <= 1) {
+    return n;
+  }
+  return fibonacci(n - 1) + fibonacci(n - 2);
+}

扁平化数组

js
//ES6的flat方法实现:
+function flatten(array) {
+  return array.flat(Infinity)
+}
+//仅限二维数组
+function flat(arr){
+  return Array.prototype.concat.apply([],arr)
+}
+let array1 = [2,3,4,[4,6,5,8]]
+flat(array1)	[2, 3, 4, 4, 6, 5, 8]
+ 
+//多维数组
+function flatplus(arr){
+  while(arr.some(item => item instanceof Array)){
+    arr = Array.prototype.concat.apply([],arr)
+  }
+  return arr
+}
+let arr = [2,3,4,[5,[6,[7]]]]
+flatplus(arr)	//[2, 3, 4, 5, 6, 7]
+
+//可控制扁平化深度:Array.prototype.concat.apply
+function flatplus(arr,depth){
+  let deep = 0	
+  let flag = arr.some(item => item instanceof Array) && deep < depth
+  while(flag){
+    arr = Array.prototype.concat.apply([],arr)
+    ++deep
+  }
+  return arr
+}
+//递归+concat
+function flatten(arr) {
+  var result = [];
+ for (var i = 0; i < arr.length; i++) {
+    if (Array.isArray(arr[i])) {
+      result = result.concat(flatten(arr[i]));
+    } else {
+      result.push(arr[i]);
+    }
+  }
+  return result;
+}
//ES6的flat方法实现:
+function flatten(array) {
+  return array.flat(Infinity)
+}
+//仅限二维数组
+function flat(arr){
+  return Array.prototype.concat.apply([],arr)
+}
+let array1 = [2,3,4,[4,6,5,8]]
+flat(array1)	[2, 3, 4, 4, 6, 5, 8]
+ 
+//多维数组
+function flatplus(arr){
+  while(arr.some(item => item instanceof Array)){
+    arr = Array.prototype.concat.apply([],arr)
+  }
+  return arr
+}
+let arr = [2,3,4,[5,[6,[7]]]]
+flatplus(arr)	//[2, 3, 4, 5, 6, 7]
+
+//可控制扁平化深度:Array.prototype.concat.apply
+function flatplus(arr,depth){
+  let deep = 0	
+  let flag = arr.some(item => item instanceof Array) && deep < depth
+  while(flag){
+    arr = Array.prototype.concat.apply([],arr)
+    ++deep
+  }
+  return arr
+}
+//递归+concat
+function flatten(arr) {
+  var result = [];
+ for (var i = 0; i < arr.length; i++) {
+    if (Array.isArray(arr[i])) {
+      result = result.concat(flatten(arr[i]));
+    } else {
+      result.push(arr[i]);
+    }
+  }
+  return result;
+}

反转字符串

js
//解法一:使用数组的reverse()方法
+function reverseString(str) {
+  return str.split('').reverse().join('');
+}
+
+//解法二:使用for循环遍历字符串
+function reverseString(str) {
+  let result = '';
+  for (let i = str.length - 1; i >= 0; i--) {
+    result += str[i];
+  }
+  return result;
+}
+
+//解法三:使用递归函数
+function reverseString(str) {
+  if (str === "")	return "";
+  return reverseString(str.slice(1)) + str[0];
+}
//解法一:使用数组的reverse()方法
+function reverseString(str) {
+  return str.split('').reverse().join('');
+}
+
+//解法二:使用for循环遍历字符串
+function reverseString(str) {
+  let result = '';
+  for (let i = str.length - 1; i >= 0; i--) {
+    result += str[i];
+  }
+  return result;
+}
+
+//解法三:使用递归函数
+function reverseString(str) {
+  if (str === "")	return "";
+  return reverseString(str.slice(1)) + str[0];
+}

求最大公约数

js
function gcd(a, b) {
+  if (b === 0) return a;
+  return gcd(b, a % b);
+}
function gcd(a, b) {
+  if (b === 0) return a;
+  return gcd(b, a % b);
+}

斐波那契数列

js
//递归实现
+function fibonacci(n){
+  if(n<=1) return n;
+  return fibonacci(n-1) + fibonacci(n-2);
+}
+
+//动态规划实现
+function fibonacci(n){
+  let f = [0,1];
+  for(let i=2;i<=n;i++){
+    f[i] = f[i-1] + f[i-2];
+  }
+  return f[n];
+}
+
+//测试
+for(let i=0;i<=10;i++){
+  console.log(`fibonacci(${i}): ${fibonacci(i)}`);
+  //输出:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
+}
//递归实现
+function fibonacci(n){
+  if(n<=1) return n;
+  return fibonacci(n-1) + fibonacci(n-2);
+}
+
+//动态规划实现
+function fibonacci(n){
+  let f = [0,1];
+  for(let i=2;i<=n;i++){
+    f[i] = f[i-1] + f[i-2];
+  }
+  return f[n];
+}
+
+//测试
+for(let i=0;i<=10;i++){
+  console.log(`fibonacci(${i}): ${fibonacci(i)}`);
+  //输出:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
+}

排序算法

冒泡排序

js
function bubbleSort(arr) {
+  let len = arr.length;
+  for (let i = 0; i < len - 1; i++) {
+      for (let j = 0; j < len - 1 - i; j++) {
+          if (arr[j] > arr[j+1]) {
+            let temp = arr[j+1];
+            arr[j+1] = arr[j];
+            arr[j] = temp;
+            /*
+            不使用额外变量交换
+            方法一:
+            [arr[j+1],arr[j]] = [arr[j],arr[j+1]]
+
+            方法二:
+            a = a + b;
+            b = a - b;
+            a = a - b;
+
+            方法三:
+            a = a ^ b;
+            b = a ^ b;
+            a = a ^ b;
+            */
+          }
+      }
+  }
+  return arr;
+}
function bubbleSort(arr) {
+  let len = arr.length;
+  for (let i = 0; i < len - 1; i++) {
+      for (let j = 0; j < len - 1 - i; j++) {
+          if (arr[j] > arr[j+1]) {
+            let temp = arr[j+1];
+            arr[j+1] = arr[j];
+            arr[j] = temp;
+            /*
+            不使用额外变量交换
+            方法一:
+            [arr[j+1],arr[j]] = [arr[j],arr[j+1]]
+
+            方法二:
+            a = a + b;
+            b = a - b;
+            a = a - b;
+
+            方法三:
+            a = a ^ b;
+            b = a ^ b;
+            a = a ^ b;
+            */
+          }
+      }
+  }
+  return arr;
+}

选择排序

排序动画图解

随机生成测试数组

js
var testArr = []
+for (var i = 0; i < 10000; i++) {
+     testArr.push(Math.floor(Math.random() * 100000))
+}
var testArr = []
+for (var i = 0; i < 10000; i++) {
+     testArr.push(Math.floor(Math.random() * 100000))
+}
js
arr = [3,7,6,9,4,5,2,8]
+const selectSort = (arr) => {
+if (!Array.isArray(arr)) {
+    throw new Error(arr + "is not Array")
+}
+for (let i = 0; i < arr.length; i++) {
+    let minIndex = i;
+    //找到arr[i]后的最小值得索引
+    for (let j = i + 1; j < arr.length; j++) {
+        if (arr[j] < arr[minIndex]) {
+            minIndex = j
+        }
+    }
+    //交换
+    let tem = arr[i]
+    arr[i] = arr[minIndex]
+    arr[minIndex] = tem
+}
+return arr
+}
arr = [3,7,6,9,4,5,2,8]
+const selectSort = (arr) => {
+if (!Array.isArray(arr)) {
+    throw new Error(arr + "is not Array")
+}
+for (let i = 0; i < arr.length; i++) {
+    let minIndex = i;
+    //找到arr[i]后的最小值得索引
+    for (let j = i + 1; j < arr.length; j++) {
+        if (arr[j] < arr[minIndex]) {
+            minIndex = j
+        }
+    }
+    //交换
+    let tem = arr[i]
+    arr[i] = arr[minIndex]
+    arr[minIndex] = tem
+}
+return arr
+}

快速排序

js
function quickSort(arr) {
+    if (arr.length <= 1) return arr;
+ 
+    const pivotIndex = Math.floor(arr.length / 2);
+	//选中心轴索引,并选取中心轴的值
+    const pivot = arr.splice(pivotIndex, 1)[0];  
+    const left = [];  
+    const right = []; 
+    for (let i = 0; i < arr.length; i++) {    
+        //与中心轴比较,小的放在左数组,大的放在右数组 
+     	arr[i] <= pivot ? left.push(arr[i]) : right.push(arr[i])
+    }  
+    return quickSort(left).concat([pivot], quickSort(right));
+};
function quickSort(arr) {
+    if (arr.length <= 1) return arr;
+ 
+    const pivotIndex = Math.floor(arr.length / 2);
+	//选中心轴索引,并选取中心轴的值
+    const pivot = arr.splice(pivotIndex, 1)[0];  
+    const left = [];  
+    const right = []; 
+    for (let i = 0; i < arr.length; i++) {    
+        //与中心轴比较,小的放在左数组,大的放在右数组 
+     	arr[i] <= pivot ? left.push(arr[i]) : right.push(arr[i])
+    }  
+    return quickSort(left).concat([pivot], quickSort(right));
+};

插入排序

以第一个数为有序数组,让后面每一个数比较找位置并插入有序数组里。

若后面待插入的数大于有序数组的最后一个数,就放在原位;

若第小于有序数组的最后一个数,则进入while循环,在有序数组中找位置:

arr[preIndex]后移索引变为preIndex+1current插入到arr[preIndex]前一位,也就是arr[preindex-1+1]

js
function insertSort(arr) {
+    let len = arr.length;
+    let preIndex, current;
+    for (let i = 1; i < len; i++) {
+        preIndex = i - 1;
+        current = arr[i];
+      //  while (preIndex >= 0 && current < arr[preIndex]) {//从大到小
+        while (preIndex >= 0 && current < arr[preIndex]) {//从小到大
+            arr[preIndex + 1] = arr[preIndex];//后移
+            preIndex--;
+        }//退出while循环时,说明插入位置找到
+        arr[preIndex + 1] = current;
+    }
+    return arr;
+}
function insertSort(arr) {
+    let len = arr.length;
+    let preIndex, current;
+    for (let i = 1; i < len; i++) {
+        preIndex = i - 1;
+        current = arr[i];
+      //  while (preIndex >= 0 && current < arr[preIndex]) {//从大到小
+        while (preIndex >= 0 && current < arr[preIndex]) {//从小到大
+            arr[preIndex + 1] = arr[preIndex];//后移
+            preIndex--;
+        }//退出while循环时,说明插入位置找到
+        arr[preIndex + 1] = current;
+    }
+    return arr;
+}

希尔排序

js
function shellSort(array) {
+    let gap = Math.floor(array.length / 2);
+
+    while (1 <= gap) {
+        // 把距离为 gap 的元素编为一个组,扫描所有组
+        for (let i = gap; i < array.length; i++) {
+            let j = 0;
+            let temp = array[i];
+
+            // 对距离为 gap 的元素组进行排序
+            for (j = i - gap; j >= 0 && temp < array[j]; j -= gap) {
+                array[j + gap] = array[j];
+            }
+            array[j + gap] = temp;
+        }
+        gap = Math.floor(gap / 2); // 减小增量
+    }
+    return array;
+}
function shellSort(array) {
+    let gap = Math.floor(array.length / 2);
+
+    while (1 <= gap) {
+        // 把距离为 gap 的元素编为一个组,扫描所有组
+        for (let i = gap; i < array.length; i++) {
+            let j = 0;
+            let temp = array[i];
+
+            // 对距离为 gap 的元素组进行排序
+            for (j = i - gap; j >= 0 && temp < array[j]; j -= gap) {
+                array[j + gap] = array[j];
+            }
+            array[j + gap] = temp;
+        }
+        gap = Math.floor(gap / 2); // 减小增量
+    }
+    return array;
+}

求两个有序数组的中位数

js
//出这两个有序数组的中位数,时间复杂度为 O(m+n)
+function findMedianSortedArrays(nums1, nums2) {
+    const mergeArr = merge(nums1, nums2); // 合并两个有序数组
+    const len = mergeArr.length;
+    // 判断合并后的数组长度,分奇偶情况求中位数
+    if(len % 2 === 0) {
+        return (mergeArr[len/2-1] + mergeArr[len/2])/2;
+    } else {
+        return mergeArr[Math.floor(len/2)];
+    }
+}
+
+// 归并排序合并两个有序数组
+function merge(nums1, nums2) {
+    const result = [];
+    let i = 0, j = 0;
+    while(i < nums1.length && j < nums2.length) {
+        if(nums1[i] < nums2[j]) {
+            result.push(nums1[i]);
+            i++;
+        } else {
+            result.push(nums2[j]);
+            j++;
+        }
+    }
+    while(i < nums1.length) {
+        result.push(nums1[i]);
+        i++;
+    }
+    while(j < nums2.length) {
+        result.push(nums2[j]);
+        j++;
+    }
+    return result;
+}
//出这两个有序数组的中位数,时间复杂度为 O(m+n)
+function findMedianSortedArrays(nums1, nums2) {
+    const mergeArr = merge(nums1, nums2); // 合并两个有序数组
+    const len = mergeArr.length;
+    // 判断合并后的数组长度,分奇偶情况求中位数
+    if(len % 2 === 0) {
+        return (mergeArr[len/2-1] + mergeArr[len/2])/2;
+    } else {
+        return mergeArr[Math.floor(len/2)];
+    }
+}
+
+// 归并排序合并两个有序数组
+function merge(nums1, nums2) {
+    const result = [];
+    let i = 0, j = 0;
+    while(i < nums1.length && j < nums2.length) {
+        if(nums1[i] < nums2[j]) {
+            result.push(nums1[i]);
+            i++;
+        } else {
+            result.push(nums2[j]);
+            j++;
+        }
+    }
+    while(i < nums1.length) {
+        result.push(nums1[i]);
+        i++;
+    }
+    while(j < nums2.length) {
+        result.push(nums2[j]);
+        j++;
+    }
+    return result;
+}
js
function findMedianSortedArrays(nums1, nums2) {
+  const merge = (arr1, arr2) => {
+    const merged = [];
+    let i = 0, j = 0;
+
+    while (i < arr1.length && j < arr2.length) {
+      if (arr1[i] < arr2[j]) merged.push(arr1[i++]);
+      else merged.push(arr2[j++]);
+    }
+
+    return [...merged, ...arr1.slice(i), ...arr2.slice(j)];
+  }
+
+  const merged = merge(nums1, nums2);
+  const mid = Math.floor(merged.length / 2);
+
+  return merged.length % 2 === 0 ? (merged[mid - 1] + merged[mid]) / 2 : merged[mid];
+}
function findMedianSortedArrays(nums1, nums2) {
+  const merge = (arr1, arr2) => {
+    const merged = [];
+    let i = 0, j = 0;
+
+    while (i < arr1.length && j < arr2.length) {
+      if (arr1[i] < arr2[j]) merged.push(arr1[i++]);
+      else merged.push(arr2[j++]);
+    }
+
+    return [...merged, ...arr1.slice(i), ...arr2.slice(j)];
+  }
+
+  const merged = merge(nums1, nums2);
+  const mid = Math.floor(merged.length / 2);
+
+  return merged.length % 2 === 0 ? (merged[mid - 1] + merged[mid]) / 2 : merged[mid];
+}

实现EventEmitter

js
//可以添加事件侦听器,触发事件,并处理异步事件
+class EventEmitter {
+  constructor() {
+    this.registry = {};
+  }
+
+  on(eventName, listener) {
+    if (!this.registry[eventName]) {
+      this.registry[eventName] = [];
+    }
+    this.registry[eventName].push(listener);
+  }
+
+  emit(eventName, ...args) {
+    if (this.registry[eventName]) {
+      this.registry[eventName].forEach((listener) => {
+        setTimeout(() => {
+          listener(...args);
+        }, 0);
+      });
+    }
+  }
+}
//可以添加事件侦听器,触发事件,并处理异步事件
+class EventEmitter {
+  constructor() {
+    this.registry = {};
+  }
+
+  on(eventName, listener) {
+    if (!this.registry[eventName]) {
+      this.registry[eventName] = [];
+    }
+    this.registry[eventName].push(listener);
+  }
+
+  emit(eventName, ...args) {
+    if (this.registry[eventName]) {
+      this.registry[eventName].forEach((listener) => {
+        setTimeout(() => {
+          listener(...args);
+        }, 0);
+      });
+    }
+  }
+}
测试
js
const eventEmitter = new EventEmitter();
+
+eventEmitter.on('eventA', () => { console.log('eventA triggered'); });
+eventEmitter.on('eventB', () => { console.log('eventB triggered'); });
+
+eventEmitter.emit('eventA');
+eventEmitter.emit('eventB');
const eventEmitter = new EventEmitter();
+
+eventEmitter.on('eventA', () => { console.log('eventA triggered'); });
+eventEmitter.on('eventB', () => { console.log('eventB triggered'); });
+
+eventEmitter.emit('eventA');
+eventEmitter.emit('eventB');

生成随机十六进制颜色

方案一:

js
function randomHexColor() {
+  var red = Math.floor(Math.random() * 256).toString(16);
+  var green = Math.floor(Math.random() * 256).toString(16);
+  var blue = Math.floor(Math.random() * 256).toString(16);
+  return "#" + red + green + blue;
+}
function randomHexColor() {
+  var red = Math.floor(Math.random() * 256).toString(16);
+  var green = Math.floor(Math.random() * 256).toString(16);
+  var blue = Math.floor(Math.random() * 256).toString(16);
+  return "#" + red + green + blue;
+}

方案二:

js
function randomHexColor() {
+  var color = Math.floor(Math.random() * 16777215).toString(16);
+  return `#${color}`;
+}
function randomHexColor() {
+  var color = Math.floor(Math.random() * 16777215).toString(16);
+  return `#${color}`;
+}

方案三:

js
function randomHexColor() {
+  var hexColor = Array.from({length: 3}, () => Math.floor(Math.random() * 256).toString(16));
+  return "#" + hexColor.join("");
+}
function randomHexColor() {
+  var hexColor = Array.from({length: 3}, () => Math.floor(Math.random() * 256).toString(16));
+  return "#" + hexColor.join("");
+}

方案四:

js
function randomHexColor() {
+  let letters = "0123456789ABCDEF";
+  let color = "#";
+  for (let i = 0; i < 6; i++) {
+     color += letters[Math.floor(Math.random() * 16)];
+  }
+  return color;
+}
function randomHexColor() {
+  let letters = "0123456789ABCDEF";
+  let color = "#";
+  for (let i = 0; i < 6; i++) {
+     color += letters[Math.floor(Math.random() * 16)];
+  }
+  return color;
+}

方案五:

js
function randomHexColor() {
+  let color = Math.floor(Math.random() * 0xFFFFFF).toString(16);
+  return "#" + ("000000" + color).slice(-6);
+}
function randomHexColor() {
+  let color = Math.floor(Math.random() * 0xFFFFFF).toString(16);
+  return "#" + ("000000" + color).slice(-6);
+}

方案六:

js
let color = '#' + parseInt(Math.random() * 0x1000000).toString(16).padStart(6, '0')
let color = '#' + parseInt(Math.random() * 0x1000000).toString(16).padStart(6, '0')

方案七:

js
function randomColor() {
+    const r = (Math.floor(Math.random() * 255)).toString(16);
+    const g = (Math.floor(Math.random() * 255)).toString(16);
+    const b = (Math.floor(Math.random() * 255)).toString(16);
+    const a = (Math.random()).toString(16).slice(2, 4);
+    return `#` + r + g + b + a;
+  }
function randomColor() {
+    const r = (Math.floor(Math.random() * 255)).toString(16);
+    const g = (Math.floor(Math.random() * 255)).toString(16);
+    const b = (Math.floor(Math.random() * 255)).toString(16);
+    const a = (Math.random()).toString(16).slice(2, 4);
+    return `#` + r + g + b + a;
+  }

返回给定起止字符串月份中间所有月份

js
function getMonths(start, end) {
+  const startDate = new Date(start);
+  const endDate = new Date(end);
+  const months = [];
+
+  while (startDate <= endDate) {
+    const year = startDate.getFullYear();
+    const month = startDate.getMonth() + 1;
+    const monthStr = `${year}-${month.toString().padStart(2, '0')}`;
+
+  	months.push(monthStr)
+    startDate.setMonth(month);
+  }
+  return months
+}
function getMonths(start, end) {
+  const startDate = new Date(start);
+  const endDate = new Date(end);
+  const months = [];
+
+  while (startDate <= endDate) {
+    const year = startDate.getFullYear();
+    const month = startDate.getMonth() + 1;
+    const monthStr = `${year}-${month.toString().padStart(2, '0')}`;
+
+  	months.push(monthStr)
+    startDate.setMonth(month);
+  }
+  return months
+}

实现Promise的all方法

js
function promiseAll(promiseArr) {
+  return new Promise((resolve, reject) => {
+     if (!Array.isArray(promiseArr)) {
+      return reject(new TypeError('arguments should be an array'));
+    }
+    const resArr = [];
+    // let count = 0;
+    // for (let i = 0; i < promiseArr.length; i++) {
+    //   promiseArr[i]
+    //     .then((res) => {
+    //       count++;
+    //       resArr[i] = res;
+    //       if (count === promiseArr.length) {
+    //         resolve(resArr);
+    //       }
+    //     })
+    //     .catch((err) => {
+    //       reject(err);
+    //     });
+    // }
+    promiseArr.forEach((p,i) =>{
+      if(p instanceof Promise){
+          p.then(res => {
+          resArr[i] = res;
+          if(resArr.length == i +1) resolve(resArr)
+        }).catch(err => reject(err))
+      }else{
+        resArr[resArr.length] = p;
+      }
+    })
+     
+  });
+}
+
+// 使用示例
+let p1 = Promise.resolve(1);
+let p2 = new Promise((resolve, reject) => {
+    setTimeout(() => {
+        resolve(2)
+    }, 2000);
+});
+let p3 = Promise.resolve("error");
+
+let p = promiseAll([p1, p2, p3])
+  .then((res) => {
+    resolve(res); // [1, 2, "error"]
+  })
+  .catch((err) => {
+    reject(err); // error
+  });
+  p.then(res => console.log(res)).catch(err => console.log(err))
function promiseAll(promiseArr) {
+  return new Promise((resolve, reject) => {
+     if (!Array.isArray(promiseArr)) {
+      return reject(new TypeError('arguments should be an array'));
+    }
+    const resArr = [];
+    // let count = 0;
+    // for (let i = 0; i < promiseArr.length; i++) {
+    //   promiseArr[i]
+    //     .then((res) => {
+    //       count++;
+    //       resArr[i] = res;
+    //       if (count === promiseArr.length) {
+    //         resolve(resArr);
+    //       }
+    //     })
+    //     .catch((err) => {
+    //       reject(err);
+    //     });
+    // }
+    promiseArr.forEach((p,i) =>{
+      if(p instanceof Promise){
+          p.then(res => {
+          resArr[i] = res;
+          if(resArr.length == i +1) resolve(resArr)
+        }).catch(err => reject(err))
+      }else{
+        resArr[resArr.length] = p;
+      }
+    })
+     
+  });
+}
+
+// 使用示例
+let p1 = Promise.resolve(1);
+let p2 = new Promise((resolve, reject) => {
+    setTimeout(() => {
+        resolve(2)
+    }, 2000);
+});
+let p3 = Promise.resolve("error");
+
+let p = promiseAll([p1, p2, p3])
+  .then((res) => {
+    resolve(res); // [1, 2, "error"]
+  })
+  .catch((err) => {
+    reject(err); // error
+  });
+  p.then(res => console.log(res)).catch(err => console.log(err))

LRU缓存算法

js
//LRU缓存算法: 缓存固定大小,当缓存超出容量时,删除最久未被使用的元素
+class LRUCache {
+  constructor(capacity) {
+    this.capacity = capacity; // 缓存最大容量
+    this.cache = new Map(); // 使用Map来存储key-value
+  }
+  //获取缓存中对应key的值,如果不存在则返回-1
+  get(key) {
+    const cache = this.cache;
+    if (!cache.has(key)) {
+      return -1;
+    }
+    const value = cache.get(key);
+    // 将访问的元素删除并重新添加到最前面
+    cache.delete(key);
+    cache.set(key, value);
+    return value;
+  }
+
+  //添加一个元素到缓存中,并在超出容量时删除最久未被使用的元素
+  put(key, value) {
+    const cache = this.cache;
+    // 如果key已经存在,则先删除这个节点
+    if (cache.has(key)) {
+      cache.delete(key);
+    } else if (cache.size >= this.capacity) {
+      // 如果缓存超出容量,则删除最久未被使用的元素,即链表尾部元素
+      const keys = cache.keys();
+      const oldestKey = keys.next().value; // 链表头部是最久未使用的元素
+      cache.delete(oldestKey);
+    }
+    // 将新节点添加到链表头部
+    cache.set(key, value);
+  }
+}
//LRU缓存算法: 缓存固定大小,当缓存超出容量时,删除最久未被使用的元素
+class LRUCache {
+  constructor(capacity) {
+    this.capacity = capacity; // 缓存最大容量
+    this.cache = new Map(); // 使用Map来存储key-value
+  }
+  //获取缓存中对应key的值,如果不存在则返回-1
+  get(key) {
+    const cache = this.cache;
+    if (!cache.has(key)) {
+      return -1;
+    }
+    const value = cache.get(key);
+    // 将访问的元素删除并重新添加到最前面
+    cache.delete(key);
+    cache.set(key, value);
+    return value;
+  }
+
+  //添加一个元素到缓存中,并在超出容量时删除最久未被使用的元素
+  put(key, value) {
+    const cache = this.cache;
+    // 如果key已经存在,则先删除这个节点
+    if (cache.has(key)) {
+      cache.delete(key);
+    } else if (cache.size >= this.capacity) {
+      // 如果缓存超出容量,则删除最久未被使用的元素,即链表尾部元素
+      const keys = cache.keys();
+      const oldestKey = keys.next().value; // 链表头部是最久未使用的元素
+      cache.delete(oldestKey);
+    }
+    // 将新节点添加到链表头部
+    cache.set(key, value);
+  }
+}

使用示例:

js
const cache = new LRUCache(2);
+
+console.log(cache.put(1, 1)); // 缓存是 {1=1}
+console.log(cache.put(2, 2)); // 缓存是 {1=1, 2=2}
+console.log(cache.get(1)); // 返回 1
+console.log(cache.put(3, 3)); // 删除 key 2,缓存是 {1=1, 3=3}
+console.log(cache.get(2)); // 返回 -1
+console.log(cache.put(4, 4)); // 删除 key 1,缓存是 {3=3, 4=4}
+console.log(cache.get(1)); // 返回 -1
+console.log(cache.get(3)); // 返回 3
+console.log(cache.get(4)); // 返回 4
const cache = new LRUCache(2);
+
+console.log(cache.put(1, 1)); // 缓存是 {1=1}
+console.log(cache.put(2, 2)); // 缓存是 {1=1, 2=2}
+console.log(cache.get(1)); // 返回 1
+console.log(cache.put(3, 3)); // 删除 key 2,缓存是 {1=1, 3=3}
+console.log(cache.get(2)); // 返回 -1
+console.log(cache.put(4, 4)); // 删除 key 1,缓存是 {3=3, 4=4}
+console.log(cache.get(1)); // 返回 -1
+console.log(cache.get(3)); // 返回 3
+console.log(cache.get(4)); // 返回 4

不使用乘法符号乘法函数

js
//递归
+function multiply(x, y) {
+  if (y === 0) {
+    return 0;
+  }
+  if (y > 0) {
+    return x + multiply(x, y - 1);
+  }
+  if (y < 0) {
+    return -multiply(x, -y);
+  }
+}
+//for循环
+function multiply(a, b) {
+  let result = 0;
+  for(let i = 0; i < Math.abs(b); i++) {
+    result += Math.abs(a);
+  }
+  if(a < 0 && b > 0 || a > 0 && b < 0) {
+    result = -result;
+  }
+  return result;
+}
+
+console.log(multiply(5, 3)); // 15
+console.log(multiply(-5, 3)); // -15
+console.log(multiply(5, -3)); // -15
+console.log(multiply(-5, -3)); // 15
//递归
+function multiply(x, y) {
+  if (y === 0) {
+    return 0;
+  }
+  if (y > 0) {
+    return x + multiply(x, y - 1);
+  }
+  if (y < 0) {
+    return -multiply(x, -y);
+  }
+}
+//for循环
+function multiply(a, b) {
+  let result = 0;
+  for(let i = 0; i < Math.abs(b); i++) {
+    result += Math.abs(a);
+  }
+  if(a < 0 && b > 0 || a > 0 && b < 0) {
+    result = -result;
+  }
+  return result;
+}
+
+console.log(multiply(5, 3)); // 15
+console.log(multiply(-5, 3)); // -15
+console.log(multiply(5, -3)); // -15
+console.log(multiply(-5, -3)); // 15

链表反转

js
function reverseLinkedList(head) {
+  let prev = null;
+  let current = head;
+  while (current !== null) {
+    let next = current.next;
+    current.next = prev;
+    prev = current;
+    current = next;
+  }
+  return prev;
+}
+
+//测试
+class Node {
+  constructor(value, next = null) {
+    this.value = value;
+    this.next = next;
+  }
+}
+
+let n1 = new Node(1);
+let n2 = new Node(2);
+let n3 = new Node(3);
+let n4 = new Node(4);
+let n5 = new Node(5);
+
+n1.next = n2;
+n2.next = n3;
+n3.next = n4;
+n4.next = n5;
+
+let head = n1;
+console.log("Original LinkedList: ");
+printLinkedList(head);
+
+head = reverseLinkedList(head);
+console.log("\nReversed LinkedList: ");
+printLinkedList(head);
+
+function printLinkedList(head) {
+  let current = head;
+  while (current !== null) {
+    process.stdout.write(current.value + " ");
+    current = current.next;
+  }
+}
function reverseLinkedList(head) {
+  let prev = null;
+  let current = head;
+  while (current !== null) {
+    let next = current.next;
+    current.next = prev;
+    prev = current;
+    current = next;
+  }
+  return prev;
+}
+
+//测试
+class Node {
+  constructor(value, next = null) {
+    this.value = value;
+    this.next = next;
+  }
+}
+
+let n1 = new Node(1);
+let n2 = new Node(2);
+let n3 = new Node(3);
+let n4 = new Node(4);
+let n5 = new Node(5);
+
+n1.next = n2;
+n2.next = n3;
+n3.next = n4;
+n4.next = n5;
+
+let head = n1;
+console.log("Original LinkedList: ");
+printLinkedList(head);
+
+head = reverseLinkedList(head);
+console.log("\nReversed LinkedList: ");
+printLinkedList(head);
+
+function printLinkedList(head) {
+  let current = head;
+  while (current !== null) {
+    process.stdout.write(current.value + " ");
+    current = current.next;
+  }
+}

二叉树的遍历

二叉树三种遍历方式

  • 前序遍历:先访问节点,然后再访问左子树和右子树。
  • 中序遍历:先访问左子树,然后访问节点,最后访问右子树。
  • 后序遍历:先访问左子树,然后访问右子树,最后访问节点。
javascript
// 定义二叉树节点类
+class TreeNode {
+  constructor(val) {
+    this.val = val;
+    this.left = null;
+    this.right = null;
+  }
+}
+
+// 前序遍历
+function preOrderTraversal(root, res = []) {
+  if (!root) return res;
+  res.push(root.val);
+  preOrderTraversal(root.left, res);
+  preOrderTraversal(root.right, res);
+  return res;
+}
+
+// 中序遍历
+function inOrderTraversal(root, res = []) {
+  if (!root) return res;
+  inOrderTraversal(root.left, res);
+  res.push(root.val);
+  inOrderTraversal(root.right, res);
+  return res;
+}
+
+// 后序遍历
+function postOrderTraversal(root, res = []) {
+  if (!root) return res;
+  postOrderTraversal(root.left, res);
+  postOrderTraversal(root.right, res);
+  res.push(root.val);
+  return res;
+}
// 定义二叉树节点类
+class TreeNode {
+  constructor(val) {
+    this.val = val;
+    this.left = null;
+    this.right = null;
+  }
+}
+
+// 前序遍历
+function preOrderTraversal(root, res = []) {
+  if (!root) return res;
+  res.push(root.val);
+  preOrderTraversal(root.left, res);
+  preOrderTraversal(root.right, res);
+  return res;
+}
+
+// 中序遍历
+function inOrderTraversal(root, res = []) {
+  if (!root) return res;
+  inOrderTraversal(root.left, res);
+  res.push(root.val);
+  inOrderTraversal(root.right, res);
+  return res;
+}
+
+// 后序遍历
+function postOrderTraversal(root, res = []) {
+  if (!root) return res;
+  postOrderTraversal(root.left, res);
+  postOrderTraversal(root.right, res);
+  res.push(root.val);
+  return res;
+}
测试
js
/* ------------- 测试 -------------- */
+
+//     1
+//   /   \
+//  2     3
+// / \   / \
+//4   5 6   7
+const root = new TreeNode(1);
+root.left = new TreeNode(2);
+root.left.left = new TreeNode(4);
+root.left.right = new TreeNode(5);
+root.right = new TreeNode(3);
+root.right.left = new TreeNode(6);
+root.right.right = new TreeNode(7);
+
+console.log(preOrderTraversal(root));   // [1, 2, 4, 5, 3, 6, 7]
+console.log(inOrderTraversal(root));    // [4, 2, 5, 1, 6, 3, 7]
+console.log(postOrderTraversal(root));  // [4, 5, 2, 6, 7, 3, 1]
/* ------------- 测试 -------------- */
+
+//     1
+//   /   \
+//  2     3
+// / \   / \
+//4   5 6   7
+const root = new TreeNode(1);
+root.left = new TreeNode(2);
+root.left.left = new TreeNode(4);
+root.left.right = new TreeNode(5);
+root.right = new TreeNode(3);
+root.right.left = new TreeNode(6);
+root.right.right = new TreeNode(7);
+
+console.log(preOrderTraversal(root));   // [1, 2, 4, 5, 3, 6, 7]
+console.log(inOrderTraversal(root));    // [4, 2, 5, 1, 6, 3, 7]
+console.log(postOrderTraversal(root));  // [4, 5, 2, 6, 7, 3, 1]

二叉搜索树的插入和查找

js
递归实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+  } else {
+    this.insertNode(this.root, newNode);
+  }
+};
+
+BST.prototype.insertNode = function(node, newNode) {
+  if (newNode.value < node.value) {
+    if (node.left === null) {
+      node.left = newNode;
+    } else {
+      this.insertNode(node.left, newNode);
+    }
+  } else {
+    if (node.right === null) {
+      node.right = newNode;
+    } else {
+      this.insertNode(node.right, newNode);
+    }
+  }
+};
+
+BST.prototype.search = function(value) { 
+  return this.searchNode(this.root, value); 
+};
+
+BST.prototype.searchNode = function(node, value) { 
+  if (node === null) {
+    return false;
+  } else if (value < node.value) {
+    return this.searchNode(node.left, value);
+  } else if (value > node.value) {
+    return this.searchNode(node.right, value);
+  } else {
+    return true;
+  }
+};
+
+循环实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+    return;
+  }
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      if (current.left === null) {
+        current.left = newNode;
+        return;
+      }
+      current = current.left;
+    } else {
+      if (current.right === null) {
+        current.right = newNode;
+        return;
+      }
+      current = current.right;
+    }
+  }
+};
+
+BST.prototype.search = function(value) {
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      current = current.left;
+    } else if (value > current.value) {
+      current = current.right;
+    } else {
+      return true;
+    }
+  }
+  return false;
+};
递归实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+  } else {
+    this.insertNode(this.root, newNode);
+  }
+};
+
+BST.prototype.insertNode = function(node, newNode) {
+  if (newNode.value < node.value) {
+    if (node.left === null) {
+      node.left = newNode;
+    } else {
+      this.insertNode(node.left, newNode);
+    }
+  } else {
+    if (node.right === null) {
+      node.right = newNode;
+    } else {
+      this.insertNode(node.right, newNode);
+    }
+  }
+};
+
+BST.prototype.search = function(value) { 
+  return this.searchNode(this.root, value); 
+};
+
+BST.prototype.searchNode = function(node, value) { 
+  if (node === null) {
+    return false;
+  } else if (value < node.value) {
+    return this.searchNode(node.left, value);
+  } else if (value > node.value) {
+    return this.searchNode(node.right, value);
+  } else {
+    return true;
+  }
+};
+
+循环实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+    return;
+  }
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      if (current.left === null) {
+        current.left = newNode;
+        return;
+      }
+      current = current.left;
+    } else {
+      if (current.right === null) {
+        current.right = newNode;
+        return;
+      }
+      current = current.right;
+    }
+  }
+};
+
+BST.prototype.search = function(value) {
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      current = current.left;
+    } else if (value > current.value) {
+      current = current.right;
+    } else {
+      return true;
+    }
+  }
+  return false;
+};

字符串搜索算法

javascript
//KMP算法是一种高效的字符串搜索算法,在对文本串和模式串进行匹配时,通过利用前缀表来避免不必要的比较,从而实现快速匹配。
+function kmp(text, pattern) {
+  let n = text.length;
+  let m = pattern.length;
+
+  // 构建前缀表
+  let prefix = Array(m).fill(0);
+  let j = 0;
+  for (let i = 1; i < m; i++) {
+    while (j > 0 && pattern[j] !== pattern[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === pattern[i]) {
+      j++;
+    }
+    prefix[i] = j;
+  }
+
+  // 匹配文本串和模式串
+  j = 0;
+  for (let i = 0; i < n; i++) {
+    while (j > 0 && pattern[j] !== text[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === text[i]) {
+      j++;
+    }
+    if (j === m) {
+      return i - m + 1;
+    }
+  }
+
+  return -1;
+}
//KMP算法是一种高效的字符串搜索算法,在对文本串和模式串进行匹配时,通过利用前缀表来避免不必要的比较,从而实现快速匹配。
+function kmp(text, pattern) {
+  let n = text.length;
+  let m = pattern.length;
+
+  // 构建前缀表
+  let prefix = Array(m).fill(0);
+  let j = 0;
+  for (let i = 1; i < m; i++) {
+    while (j > 0 && pattern[j] !== pattern[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === pattern[i]) {
+      j++;
+    }
+    prefix[i] = j;
+  }
+
+  // 匹配文本串和模式串
+  j = 0;
+  for (let i = 0; i < n; i++) {
+    while (j > 0 && pattern[j] !== text[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === text[i]) {
+      j++;
+    }
+    if (j === m) {
+      return i - m + 1;
+    }
+  }
+
+  return -1;
+}

在这个函数中,我们首先计算出模式串的前缀表,然后逐个字符地扫描文本串和模式串,利用前缀表来确定匹配的位置。

接下来,我们可以使用这个函数来测试一下:

javascript
let text = "hello world";
+let pattern = "world";
+let index = kmp(text, pattern);
+console.log(index); // 输出5
let text = "hello world";
+let pattern = "world";
+let index = kmp(text, pattern);
+console.log(index); // 输出5

在这个例子中,我们将文本串设置为“hello world”,将模式串设置为“world”,然后调用kmp函数来查找匹配位置。由于模式串出现在文本串的位置是5,所以kmp函数返回的结果也是5。

这里还可以尝试一些其他的测试用例,例如:

javascript
let text = "abababaababacb";
+let pattern = "ababacb";
+let index = kmp(text, pattern);
+console.log(index); // 输出7
let text = "abababaababacb";
+let pattern = "ababacb";
+let index = kmp(text, pattern);
+console.log(index); // 输出7

这个例子中,我们将文本串设置为“abababaababacb”,将模式串设置为“ababacb”,然后调用kmp函数来查找匹配位置。由于模式串出现在文本串的位置是7,所以kmp函数返回的结果也是7。

总之,KMP算法是一种高效的字符串搜索算法,通过利用前缀表来避免不必要的比较,能够快速地查找匹配位置。

数字转中文

方法一:

js
function numberToChinese(num, upper = false) {
+  if (!/^(\-|\+)?\d*(\.\d*)?$/.test(num)) {
+    return "不是一个合法的数字!";
+  }
+  let digitMap = {
+    plain:["", "", "", "", "", "", "", "", "", ""],
+    upper:["", "", "", "", "", "", "", "", "", ""]
+  }
+  let unitMap = {
+    plain: [
+      ["", "", "亿"],
+      ["", "", "", ""],
+    ],
+    upper: [
+      ["", "", ""],
+      ["", "", "", ""],
+    ],
+  };
+  let ustr = upper ? "upper" : "plain"
+  let head = num < 0 ? "" : "";
+  let unit = unitMap[ustr];
+  num = Math.abs(num);
+  let result = "";
+  for (let i = 0; i < unit[0].length && num > 0; i++) {
+    let currUnit = "";
+    for (let j = 0; j < unit[1].length && num > 0; j++) {
+      let index = num % 10;
+      let d =digitMap[ustr];
+      currUnit = d + unit[1][j] + currUnit;
+      num = Math.floor(num / 10);
+    }
+    result =
+      currUnit.replace(/(.)*$/, "").replace(/^$/, "") +
+      unit[0][i] +
+      result;
+  }
+  let reg = upper ? /億零{0,3}/ : /亿零{0,3}/;
+  let lastres =
+    head +
+    result
+      .replace(/(.)*零元/, "")
+      .replace(/(.)+/g, "")
+      .replace(reg, upper ? "" : "亿")
+      .replace(/^+/, "");
+  return lastres;
+}
function numberToChinese(num, upper = false) {
+  if (!/^(\-|\+)?\d*(\.\d*)?$/.test(num)) {
+    return "不是一个合法的数字!";
+  }
+  let digitMap = {
+    plain:["", "", "", "", "", "", "", "", "", ""],
+    upper:["", "", "", "", "", "", "", "", "", ""]
+  }
+  let unitMap = {
+    plain: [
+      ["", "", "亿"],
+      ["", "", "", ""],
+    ],
+    upper: [
+      ["", "", ""],
+      ["", "", "", ""],
+    ],
+  };
+  let ustr = upper ? "upper" : "plain"
+  let head = num < 0 ? "" : "";
+  let unit = unitMap[ustr];
+  num = Math.abs(num);
+  let result = "";
+  for (let i = 0; i < unit[0].length && num > 0; i++) {
+    let currUnit = "";
+    for (let j = 0; j < unit[1].length && num > 0; j++) {
+      let index = num % 10;
+      let d =digitMap[ustr];
+      currUnit = d + unit[1][j] + currUnit;
+      num = Math.floor(num / 10);
+    }
+    result =
+      currUnit.replace(/(.)*$/, "").replace(/^$/, "") +
+      unit[0][i] +
+      result;
+  }
+  let reg = upper ? /億零{0,3}/ : /亿零{0,3}/;
+  let lastres =
+    head +
+    result
+      .replace(/(.)*零元/, "")
+      .replace(/(.)+/g, "")
+      .replace(reg, upper ? "" : "亿")
+      .replace(/^+/, "");
+  return lastres;
+}

方法二:

js
function numberToChinese(num) {
+  if (num === 0) return "";
+  //数字超过999999999999则报错
+  if (num.toString().length > 12) {
+    throw new Error("数字过大,无法转换");
+  }
+  let cstr = "";
+  let bunits = ["", "", "亿"];
+  //把数字转换成字符串,四位一组,从后往前分割
+  let numStr = num
+    .toString()
+    .split("")
+    .reverse()
+    .join("")
+    .match(/(\d{1,4})/g)
+    .join(",")
+    .split("")
+    .reverse()
+    .join("")
+    .split(",");
+  let len = numStr.length;
+
+  function transform(str) {
+    let res = "";
+    let carr = ["", "", "", "", "", "", "", "", "", ""];
+    let units = ["", "", "", ""];
+    for (let i = 0; i < str.length; i++) {
+      let digit = +str[i];
+      let char = carr[digit];
+      let unit = units[str.length - i - 1];
+      if (digit === 0) {
+        //如果是0,且不是最后一位不是零,则加零,并且不加单位
+        if (res[res.length - 1] !== "") {
+          res += char;
+        }
+      } else {
+        res += char + unit;
+      }
+    }
+    if (res[res.length - 1] === "") {
+      res = res.slice(0, res.length - 1);
+    }
+    return res;
+  }
+  for (let i = 0; i < len; i++) {
+    let part = numStr[i];
+    let str = transform(part);
+    let unit = str ? bunits[len - i - 1] : "";
+    cstr += str + unit;
+  }
+  cstr.startsWith("一十") && (cstr = cstr.slice(1));
+  return cstr;
+}
+
+//大写中文
+function bigChinese(str){
+  let  map ={
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '亿':'',
+  }
+  let s = numberToChinese(str)
+  return s.split('').map( item => map[item]).join('')
+
+}
+let n = bigChinese(1000100001); //拾億零壹拾萬零壹
+console.log('[ n ]-66', n)
function numberToChinese(num) {
+  if (num === 0) return "";
+  //数字超过999999999999则报错
+  if (num.toString().length > 12) {
+    throw new Error("数字过大,无法转换");
+  }
+  let cstr = "";
+  let bunits = ["", "", "亿"];
+  //把数字转换成字符串,四位一组,从后往前分割
+  let numStr = num
+    .toString()
+    .split("")
+    .reverse()
+    .join("")
+    .match(/(\d{1,4})/g)
+    .join(",")
+    .split("")
+    .reverse()
+    .join("")
+    .split(",");
+  let len = numStr.length;
+
+  function transform(str) {
+    let res = "";
+    let carr = ["", "", "", "", "", "", "", "", "", ""];
+    let units = ["", "", "", ""];
+    for (let i = 0; i < str.length; i++) {
+      let digit = +str[i];
+      let char = carr[digit];
+      let unit = units[str.length - i - 1];
+      if (digit === 0) {
+        //如果是0,且不是最后一位不是零,则加零,并且不加单位
+        if (res[res.length - 1] !== "") {
+          res += char;
+        }
+      } else {
+        res += char + unit;
+      }
+    }
+    if (res[res.length - 1] === "") {
+      res = res.slice(0, res.length - 1);
+    }
+    return res;
+  }
+  for (let i = 0; i < len; i++) {
+    let part = numStr[i];
+    let str = transform(part);
+    let unit = str ? bunits[len - i - 1] : "";
+    cstr += str + unit;
+  }
+  cstr.startsWith("一十") && (cstr = cstr.slice(1));
+  return cstr;
+}
+
+//大写中文
+function bigChinese(str){
+  let  map ={
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '亿':'',
+  }
+  let s = numberToChinese(str)
+  return s.split('').map( item => map[item]).join('')
+
+}
+let n = bigChinese(1000100001); //拾億零壹拾萬零壹
+console.log('[ n ]-66', n)
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\346\211\213\345\206\231Promise.html" "b/FrontEnd/JavaScript/\346\211\213\345\206\231Promise.html" new file mode 100644 index 00000000..c031ed45 --- /dev/null +++ "b/FrontEnd/JavaScript/\346\211\213\345\206\231Promise.html" @@ -0,0 +1,1179 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、声名Promise并绑定this

js
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        }
+        // 3.成功状态
+    resolve(value) {
+            this.status = Promise.FUFILLED
+            this.value = value
+        }
+        // 4.失败状态
+    reject(reason) {
+        this.status = Promise.REJECTED
+        this.reason = reason
+    }
+}
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        }
+        // 3.成功状态
+    resolve(value) {
+            this.status = Promise.FUFILLED
+            this.value = value
+        }
+        // 4.失败状态
+    reject(reason) {
+        this.status = Promise.REJECTED
+        this.reason = reason
+    }
+}

问题一:能多次修改状态

html
<!DOCTYPE html>
+
+<head>
+    <title>My-Promise</title>
+    <script src="./Promise.js"></script>
+</head>
+
+<body>
+    <script>
+        var p1 = new Promise((resolve, reject) => {
+            resolve('大功告成!')
+            reject('一败涂地!')
+        })
+        console.log(p1);
+    </script>
+</body>
+
+</html>
<!DOCTYPE html>
+
+<head>
+    <title>My-Promise</title>
+    <script src="./Promise.js"></script>
+</head>
+
+<body>
+    <script>
+        var p1 = new Promise((resolve, reject) => {
+            resolve('大功告成!')
+            reject('一败涂地!')
+        })
+        console.log(p1);
+    </script>
+</body>
+
+</html>

二、状态保护与执行者异步捕获

改变状态前先判断,让初始状态只能修改一次

js
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            try {
+                executor(this.resolve.bind(this), this.reject.bind(this))
+            } catch {
+
+            }
+
+        }
+        // 3.成功状态
+    resolve(value) {
+            //判断是不是初始态
+            if (this.status == Promise.PENDING) {
+                this.status = Promise.FUFILLED
+                this.value = value
+            }
+
+        }
+        // 4.失败状态
+    reject(reason) {
+        //判断是不是初始态
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED
+            this.reason = reason
+        }
+    }
+}
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            try {
+                executor(this.resolve.bind(this), this.reject.bind(this))
+            } catch {
+
+            }
+
+        }
+        // 3.成功状态
+    resolve(value) {
+            //判断是不是初始态
+            if (this.status == Promise.PENDING) {
+                this.status = Promise.FUFILLED
+                this.value = value
+            }
+
+        }
+        // 4.失败状态
+    reject(reason) {
+        //判断是不是初始态
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED
+            this.reason = reason
+        }
+    }
+}

三、then方法构建

js
 then(onFulfilled, onRejected) {
+        if (typeof onFulfilled !== 'function') {
+            onFulfilled = () => {}
+        }
+        if (typeof onRejected !== 'function') {
+            onRejected = () => {}
+        }
+        if (this.status == Promise.FUFILLED) {
+            onFulfilled(this.value)
+        }
+        if (this.status == Promise.REJECTED) {
+            onRejected(this.value)
+        }
+    }
 then(onFulfilled, onRejected) {
+        if (typeof onFulfilled !== 'function') {
+            onFulfilled = () => {}
+        }
+        if (typeof onRejected !== 'function') {
+            onRejected = () => {}
+        }
+        if (this.status == Promise.FUFILLED) {
+            onFulfilled(this.value)
+        }
+        if (this.status == Promise.REJECTED) {
+            onRejected(this.value)
+        }
+    }

四、实现then异步

js
if (this.status == Promise.FUFILLED) {
+    setTimeout(() => {
+        try {
+            onFulfilled(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            onRejected(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+        }
if (this.status == Promise.FUFILLED) {
+    setTimeout(() => {
+        try {
+            onFulfilled(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            onRejected(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+        }

五、解决同步代码需要等待执行问题

js
var p1 = new Promise((resolve, reject) => {
+        // resolve('大功告成!')S
+        setTimeout(() => {
+            reject('一败涂地!')
+            console.log('反败为胜!');
+        }, 100)
+
+    })
+    p1.then((value) => {
+        console.log(value);
+    }, (reason) => {
+        console.log(reason);
+    })
+    console.log('同步代码');
var p1 = new Promise((resolve, reject) => {
+        // resolve('大功告成!')S
+        setTimeout(() => {
+            reject('一败涂地!')
+            console.log('反败为胜!');
+        }, 100)
+
+    })
+    p1.then((value) => {
+        console.log(value);
+    }, (reason) => {
+        console.log(reason);
+    })
+    console.log('同步代码');

解决前输出: 同步代码 一败涂地! 反败为胜!

js
    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onRejected(value);
+                });
+            });
+        }
+    }
    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onRejected(value);
+                });
+            });
+        }
+    }

解决后输出: 同步代码 反败为胜! 一败涂地!

六、then的链式操作

注意点:

  1. then返回的时Promise,Promise需要改变
  2. 之前的Promise状态并不会影响之后的Promise状态
js
let p = new Promise((resolve, reject) => {
+        resolve("大功告成!");
+        // reject("一败涂地!");
+        console.log("状态绑定成功!");
+    })
+    p.then(
+            value => {
+                console.log(value);
+                return "马到功成!";
+            },
+            reason => {
+                console.log(reason);
+                return '优胜劣败!'
+            }
+        )
+        .then(
+            value => {
+                console.log(value);
+            },
+            reason => {
+                console.log(reason);
+            }
+        );
+    console.log("同步代码");
let p = new Promise((resolve, reject) => {
+        resolve("大功告成!");
+        // reject("一败涂地!");
+        console.log("状态绑定成功!");
+    })
+    p.then(
+            value => {
+                console.log(value);
+                return "马到功成!";
+            },
+            reason => {
+                console.log(reason);
+                return '优胜劣败!'
+            }
+        )
+        .then(
+            value => {
+                console.log(value);
+            },
+            reason => {
+                console.log(reason);
+            }
+        );
+    console.log("同步代码");
js
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        //then的穿透处理
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+         //then的穿透处理
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    try {
+                        let result = onFulfilled(value);
+                        resolve(result);
+                    } catch (error) {
+                        reject(error);
+                    }
+                },
+                onRejected: value => {
+                    try {
+                        let result = onRejected(value);
+                        resolve(result);
+                    } catch (error) { 
+                        reject(error);
+                    }
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                try {
+                    let result = onFulfilled(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                try {
+                    let result = onRejected(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+    });
+}
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        //then的穿透处理
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+         //then的穿透处理
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    try {
+                        let result = onFulfilled(value);
+                        resolve(result);
+                    } catch (error) {
+                        reject(error);
+                    }
+                },
+                onRejected: value => {
+                    try {
+                        let result = onRejected(value);
+                        resolve(result);
+                    } catch (error) { 
+                        reject(error);
+                    }
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                try {
+                    let result = onFulfilled(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                try {
+                    let result = onRejected(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+    });
+}

执行结果:

七、返回值的判断与处理

判断并分别处理返回值为Promise、普通值的情况

js
if (this.status == Promise.FULFILLED) {
+    setTimeout(() => {
+        try {
+            let result = onFulfilled(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            let result = onRejected(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}
if (this.status == Promise.FULFILLED) {
+    setTimeout(() => {
+        try {
+            let result = onFulfilled(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            let result = onRejected(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}

八、代码优化及复用

js
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    // try {
+                    //     let result = onFulfilled(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     reject(error);
+                    // }
+                    this.parse(onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    // try {
+                    //     let result = onRejected(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     //解决异常
+                    //     reject(error);
+                    // }
+                    this.parse(onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onFulfilled(this.value);
+                //     // resolve(result)
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onRejected(this.value);
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+}
+//抽取方法
+parse(result, resolve, reject) {
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    // try {
+                    //     let result = onFulfilled(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     reject(error);
+                    // }
+                    this.parse(onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    // try {
+                    //     let result = onRejected(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     //解决异常
+                    //     reject(error);
+                    // }
+                    this.parse(onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onFulfilled(this.value);
+                //     // resolve(result)
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onRejected(this.value);
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+}
+//抽取方法
+parse(result, resolve, reject) {
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}

九、返回类型约束

当前Promise不能返回自己

js
let p = promise.then(value => return p) //原生的会报错:TypeError
let p = promise.then(value => return p) //原生的会报错:TypeError
js
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    let promise = new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                this.parse(promise, onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                this.parse(promise, onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+    return promise;
+}
+parse(promise, result, resolve, reject) {
+    if (promise == result) {
+        throw new TypeError("Chaining cycle detected for promise");
+    }
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    let promise = new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                this.parse(promise, onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                this.parse(promise, onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+    return promise;
+}
+parse(promise, result, resolve, reject) {
+    if (promise == result) {
+        throw new TypeError("Chaining cycle detected for promise");
+    }
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}

十、实现resolve和reject

js
 static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }
 static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }

十一、Promise.all()实现

js
static all(promises) {
+    let resolves = [];
+    return new Promise((resolve, reject) => {
+        promises.forEach((promise, index) => {
+            promise.then(
+                value => {
+                    resolves.push(value);
+                    //判断数组长度,来看是否全部成功
+                    if (resolves.length == promises.length) {
+                        resolve(resolves);
+                    }
+                },
+                reason => {
+                    reject(reason);
+                }
+            );
+        });
+    });
+}
static all(promises) {
+    let resolves = [];
+    return new Promise((resolve, reject) => {
+        promises.forEach((promise, index) => {
+            promise.then(
+                value => {
+                    resolves.push(value);
+                    //判断数组长度,来看是否全部成功
+                    if (resolves.length == promises.length) {
+                        resolve(resolves);
+                    }
+                },
+                reason => {
+                    reject(reason);
+                }
+            );
+        });
+    });
+}

测试

js
let p1 = new Promise((resolve, reject) => {
+        resolve("成功");
+    });
+let p2 = new Promise((resolve, reject) => {
+    reject("失败");
+});
+//所有成功才会执行成功的回调函数
+let promises = Promise.all([p1, p2]).then(
+    promises => {
+        console.log('resolve:', promises);
+    },
+    reason => {
+        console.log('reject:', reason);
+    }
+);
let p1 = new Promise((resolve, reject) => {
+        resolve("成功");
+    });
+let p2 = new Promise((resolve, reject) => {
+    reject("失败");
+});
+//所有成功才会执行成功的回调函数
+let promises = Promise.all([p1, p2]).then(
+    promises => {
+        console.log('resolve:', promises);
+    },
+    reason => {
+        console.log('reject:', reason);
+    }
+);

十二、实现Promise.race()

js
const p = Promise.race([p1, p2, p3]);
const p = Promise.race([p1, p2, p3]);

只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变;率先改变的 Promise 实例的返回值,就传递给p的回调函数。 (谁快用谁)

js
 static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }
 static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }

测试

js
 let p1 = new Promise(resolve => {
+        setInterval(() => {
+            resolve("成功1");
+        }, 1000);
+    });
+let p2 = new Promise(resolve => {
+    setInterval(() => {
+        resolve("成功2");
+    }, 500);
+});
+let promises = Promise.race([p1, p2]).then(
+    promises => {
+        console.log(promises);
+    },
+    reason => {
+        console.log(reason);
+    }
+);
 let p1 = new Promise(resolve => {
+        setInterval(() => {
+            resolve("成功1");
+        }, 1000);
+    });
+let p2 = new Promise(resolve => {
+    setInterval(() => {
+        resolve("成功2");
+    }, 500);
+});
+let promises = Promise.race([p1, p2]).then(
+    promises => {
+        console.log(promises);
+    },
+    reason => {
+        console.log(reason);
+    }
+);

十三、完整代码

js
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+
+    // 2.构造函数
+    constructor(executor) {
+        //初始态
+        this.status = Promise.PENDING
+        this.value = null
+        this.callbacks = []
+        // 绑定this    
+        try {
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        } catch (error) {
+
+        }
+
+    }
+    //3.resolve改变状态并执行回调函数
+    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                //遍历回调函数数组,传值并执行onFulfilled函数
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+  //3. reject改变状态并执行回调函数
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+             setTimeout(() => {
+                 //遍历回调函数数组,传值并执行onRejected函数
+            this.callbacks.map(callback => {
+                callback.onRejected(value);
+          	  });
+            });
+        }
+    }
+
+
+//then方法
+    then(onFulfilled, onRejected) {
+        //判断参数是否为函数
+        if (typeof onFulfilled != "function") {
+            onFulfilled = value => value;
+        }
+        if (typeof onRejected != "function") {
+            onRejected = value => value;
+        }
+        let promise = new Promise((resolve, reject) => {
+            //初始态把回调函数存入数组
+            if (this.status == Promise.PENDING) {
+                this.callbacks.push({
+                    onFulfilled: value => {
+                        this.parse(promise, onFulfilled(this.value), resolve, reject);
+                    },
+                    onRejected: value => {
+                        this.parse(promise, onRejected(this.value), resolve, reject);
+                    }
+                });
+            }
+            //成功
+            if (this.status == Promise.FULFILLED) {
+                setTimeout(() => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                });
+            }
+            //失败
+            if (this.status == Promise.REJECTED) {
+                setTimeout(() => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                });
+            }
+        });
+        //解决链式调用
+        return promise;
+    }
+    parse(promise, result, resolve, reject) {
+        //不能返回自身promise
+        if (promise == result) {
+            throw new TypeError("Chaining cycle detected for promise");
+        }
+        try {
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    }
+    static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }
+
+    static all(promises) {
+        let resolves = [];
+        return new Promise((resolve, reject) => {
+            //遍历每一个promise并执行
+            promises.forEach((promise, index) => {
+                promise.then(
+                    value => {
+                        resolves.push(value);//保存
+                        if (resolves.length == promises.length) {
+                            resolve(resolves);
+                        }
+                    },
+                    reason => {
+                        reject(reason);
+                    }
+                );
+            });
+        });
+    }
+    static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }
+}
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+
+    // 2.构造函数
+    constructor(executor) {
+        //初始态
+        this.status = Promise.PENDING
+        this.value = null
+        this.callbacks = []
+        // 绑定this    
+        try {
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        } catch (error) {
+
+        }
+
+    }
+    //3.resolve改变状态并执行回调函数
+    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                //遍历回调函数数组,传值并执行onFulfilled函数
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+  //3. reject改变状态并执行回调函数
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+             setTimeout(() => {
+                 //遍历回调函数数组,传值并执行onRejected函数
+            this.callbacks.map(callback => {
+                callback.onRejected(value);
+          	  });
+            });
+        }
+    }
+
+
+//then方法
+    then(onFulfilled, onRejected) {
+        //判断参数是否为函数
+        if (typeof onFulfilled != "function") {
+            onFulfilled = value => value;
+        }
+        if (typeof onRejected != "function") {
+            onRejected = value => value;
+        }
+        let promise = new Promise((resolve, reject) => {
+            //初始态把回调函数存入数组
+            if (this.status == Promise.PENDING) {
+                this.callbacks.push({
+                    onFulfilled: value => {
+                        this.parse(promise, onFulfilled(this.value), resolve, reject);
+                    },
+                    onRejected: value => {
+                        this.parse(promise, onRejected(this.value), resolve, reject);
+                    }
+                });
+            }
+            //成功
+            if (this.status == Promise.FULFILLED) {
+                setTimeout(() => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                });
+            }
+            //失败
+            if (this.status == Promise.REJECTED) {
+                setTimeout(() => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                });
+            }
+        });
+        //解决链式调用
+        return promise;
+    }
+    parse(promise, result, resolve, reject) {
+        //不能返回自身promise
+        if (promise == result) {
+            throw new TypeError("Chaining cycle detected for promise");
+        }
+        try {
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    }
+    static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }
+
+    static all(promises) {
+        let resolves = [];
+        return new Promise((resolve, reject) => {
+            //遍历每一个promise并执行
+            promises.forEach((promise, index) => {
+                promise.then(
+                    value => {
+                        resolves.push(value);//保存
+                        if (resolves.length == promises.length) {
+                            resolve(resolves);
+                        }
+                    },
+                    reason => {
+                        reject(reason);
+                    }
+                );
+            });
+        });
+    }
+    static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.html" "b/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.html" new file mode 100644 index 00000000..83cccb70 --- /dev/null +++ "b/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.html" @@ -0,0 +1,559 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

去重的核心:要根据实际业务怎么定义'重'

基本数据类型

js
const arr = [1, 2, 1, 3];
+//用Set去重
+const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
+//用filter去重
+const uniqueArr = arr => arr.filter((item, index) => arr.indexOf(item) === index); // 相同的元素只保留一个
+ 
+//indexOf
+const uniqueArr = (arr)  =>{
+   let newArr = [];
+  for (let i = 0; i < arr.length; i++) {
+    if (newArr.indexOf(arr[i]) === -1) {//或 !newArr.includes(arr[i])
+      newArr.push(arr[i]);
+    }
+  }
+  return newArr;
+}
+
+//==> reduce与 includes
+const uniqueArr = (arr)  => arr.reduce((newArr,item) => newArr.includes(item) ? newArr : [...newArr,item],[])
+
+//双重循环遍历数组去重
+const arr = [1, 2, 2, 3, 3, 3];
+const uniqueArr = [];
+for (let i = 0; i < arr.length; i++) {
+  let isDuplicate = false;
+  for (let j = 0; j < uniqueArr.length; j++) {
+    if (arr[i] === uniqueArr[j]) {
+      isDuplicate = true;
+      break;
+    }
+  }
+  if (!isDuplicate) {
+    uniqueArr.push(arr[i]);
+  }
+}
+console.log(uniqueArr); // [1, 2, 3]
const arr = [1, 2, 1, 3];
+//用Set去重
+const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
+//用filter去重
+const uniqueArr = arr => arr.filter((item, index) => arr.indexOf(item) === index); // 相同的元素只保留一个
+ 
+//indexOf
+const uniqueArr = (arr)  =>{
+   let newArr = [];
+  for (let i = 0; i < arr.length; i++) {
+    if (newArr.indexOf(arr[i]) === -1) {//或 !newArr.includes(arr[i])
+      newArr.push(arr[i]);
+    }
+  }
+  return newArr;
+}
+
+//==> reduce与 includes
+const uniqueArr = (arr)  => arr.reduce((newArr,item) => newArr.includes(item) ? newArr : [...newArr,item],[])
+
+//双重循环遍历数组去重
+const arr = [1, 2, 2, 3, 3, 3];
+const uniqueArr = [];
+for (let i = 0; i < arr.length; i++) {
+  let isDuplicate = false;
+  for (let j = 0; j < uniqueArr.length; j++) {
+    if (arr[i] === uniqueArr[j]) {
+      isDuplicate = true;
+      break;
+    }
+  }
+  if (!isDuplicate) {
+    uniqueArr.push(arr[i]);
+  }
+}
+console.log(uniqueArr); // [1, 2, 3]

如果要去重一个包含不同数据类型的数组,需要添加一些额外的检查。

Date类型转换成Unix时间戳,RegExp类型转换成字符串。

js
const arr = ["a", "b", 1, 1, "a", /abc/, /abc/, new Date(), new Date()];
+
+const isObject = val => Object(val) === val;//判断是否为对象
+const uniqueArr = (arr) =>[...new Set(arr.map(item => {
+ if (!isObject(item))  return item //不是
+    if (item instanceof Date) {
+      return item.getTime();
+    } else if (item instanceof RegExp) {
+      return item.toString();
+    }
+}))];
+ uniqueArr(arr); // ['a', 'b', 1, '/abc/', 1678519417983]
const arr = ["a", "b", 1, 1, "a", /abc/, /abc/, new Date(), new Date()];
+
+const isObject = val => Object(val) === val;//判断是否为对象
+const uniqueArr = (arr) =>[...new Set(arr.map(item => {
+ if (!isObject(item))  return item //不是
+    if (item instanceof Date) {
+      return item.getTime();
+    } else if (item instanceof RegExp) {
+      return item.toString();
+    }
+}))];
+ uniqueArr(arr); // ['a', 'b', 1, '/abc/', 1678519417983]

对象数组去重

对象相同比较

基本思路

  1. 首先判断两个值的类型是否相同,如果不同,则返回 false
  2. 处理特殊情况 null、undefined、Date、function
  3. 处理数组类型,对比项的数量,再递归对比每个项是否相等;
  4. 处理朴素对象,对比键的数量,相等则再递归对比值是否相等。
javascript
function isEqual(obj1, obj2) {
+  const equalType = (val1,val2) => Object.prototype.toString.call(val1)!== Object.prototype.toString.call(val2)
+  // 判断类型是否一致
+  if (equalType(obj1,obj2)) {
+    return false;
+  }
+
+  // 判断 null 和 undefined:只要有一个为 null 或 undefined,则直接比较值
+  if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
+    return obj1 === obj2;
+  }
+
+  // 判断基本类型是否相等
+  if (typeof obj1 === 'number' || typeof obj1 === 'string' || typeof obj1 === 'boolean') {
+    return obj1 === obj2;
+  }
+  if (typeof obj1 === "function" && typeof obj2 === "function") return obj1.toString() === obj2.toString();
+
+  if (obj1 instanceof Date && obj2 instanceof Date) return obj1.getTime() === obj2.getTime();
+
+  // 判断数组是否相等
+  if (Array.isArray(obj1)) {
+    if (!Array.isArray(obj2) || obj1.length !== obj2.length) {
+      return false;
+    }
+   return obj1.every((item,index) => isEqual(item, obj2[index]) )
+    // for (let i = 0; i < obj1.length; i++) {
+    //   if (!isEqual(obj1[i], obj2[i])) {
+    //     return false;
+    //   }
+    // }
+    // return true;
+  }
+  //比较对象是否相等
+  //Object.keys: 返回对象自身的所有可枚举的属性的键名,不包含 Symbol 类型键名
+  //Reflect.ownKeys(): 返回所有类型的键名,包括常规键名和 Symbol 键名。
+  const keys1 = Object.keys(obj1);
+  const keys2 = Object.keys(obj2);
+  if (keys1.length !== keys2.length) {
+    return false;
+  }
+  for (const key of keys1) {
+    if (!isEqual(obj1[key], obj2[key])) {
+      return false;
+    }
+  }
+  return true;
+}
function isEqual(obj1, obj2) {
+  const equalType = (val1,val2) => Object.prototype.toString.call(val1)!== Object.prototype.toString.call(val2)
+  // 判断类型是否一致
+  if (equalType(obj1,obj2)) {
+    return false;
+  }
+
+  // 判断 null 和 undefined:只要有一个为 null 或 undefined,则直接比较值
+  if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
+    return obj1 === obj2;
+  }
+
+  // 判断基本类型是否相等
+  if (typeof obj1 === 'number' || typeof obj1 === 'string' || typeof obj1 === 'boolean') {
+    return obj1 === obj2;
+  }
+  if (typeof obj1 === "function" && typeof obj2 === "function") return obj1.toString() === obj2.toString();
+
+  if (obj1 instanceof Date && obj2 instanceof Date) return obj1.getTime() === obj2.getTime();
+
+  // 判断数组是否相等
+  if (Array.isArray(obj1)) {
+    if (!Array.isArray(obj2) || obj1.length !== obj2.length) {
+      return false;
+    }
+   return obj1.every((item,index) => isEqual(item, obj2[index]) )
+    // for (let i = 0; i < obj1.length; i++) {
+    //   if (!isEqual(obj1[i], obj2[i])) {
+    //     return false;
+    //   }
+    // }
+    // return true;
+  }
+  //比较对象是否相等
+  //Object.keys: 返回对象自身的所有可枚举的属性的键名,不包含 Symbol 类型键名
+  //Reflect.ownKeys(): 返回所有类型的键名,包括常规键名和 Symbol 键名。
+  const keys1 = Object.keys(obj1);
+  const keys2 = Object.keys(obj2);
+  if (keys1.length !== keys2.length) {
+    return false;
+  }
+  for (const key of keys1) {
+    if (!isEqual(obj1[key], obj2[key])) {
+      return false;
+    }
+  }
+  return true;
+}
测试示例
js
// 示例
+const obj1 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj2 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj3 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+};
+isEqual(obj1, obj2) // true
+isEqual(obj1, obj3) // false
+isEqual(undefined, null)// false
+isEqual(null, null)
// 示例
+const obj1 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj2 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj3 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+};
+isEqual(obj1, obj2) // true
+isEqual(obj1, obj3) // false
+isEqual(undefined, null)// false
+isEqual(null, null)

对象数组去重

js

+const arr = [1,2,3,1]
+
+//深拷贝
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}
+
+const uniqueArr(arr){
+  const newArr = deepClone(arr)
+  let len = newArr.length
+  for(let i = 0; i < len; i++){
+    for(let j = i + 1; j < len; j++){
+      if(isEqual(newArr[i], newArr[j])){
+        newArr.splice(j,1)
+      }
+    }
+  }
+  return newArr
+}

+const arr = [1,2,3,1]
+
+//深拷贝
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}
+
+const uniqueArr(arr){
+  const newArr = deepClone(arr)
+  let len = newArr.length
+  for(let i = 0; i < len; i++){
+    for(let j = i + 1; j < len; j++){
+      if(isEqual(newArr[i], newArr[j])){
+        newArr.splice(j,1)
+      }
+    }
+  }
+  return newArr
+}
测试数据
js
let objArr1 = [
+  {a:1,b:2},
+  {a:2,b:3},
+  {b:2,a:1},
+  {a:3,b:2},
+  [1,2,3],
+  [4,5,6],
+  [2,1,3],
+  {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+     console.log(2)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-11'),
+    func:function(){
+     console.log(2)
+    }
+  }
+}
+]
+//uniqueArr(objArr1)
let objArr1 = [
+  {a:1,b:2},
+  {a:2,b:3},
+  {b:2,a:1},
+  {a:3,b:2},
+  [1,2,3],
+  [4,5,6],
+  [2,1,3],
+  {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+     console.log(2)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-11'),
+    func:function(){
+     console.log(2)
+    }
+  }
+}
+]
+//uniqueArr(objArr1)
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.html" "b/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.html" new file mode 100644 index 00000000..10fd6f9d --- /dev/null +++ "b/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.html" @@ -0,0 +1,189 @@ + + + + + + JS常用的求交集、并集、差集的方法 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

JS常用的求交集、并集、差集的方法

普通数组

示例数组

js
let a = [1, 2, 3];
+let b = [4, 3, 2];
let a = [1, 2, 3];
+let b = [4, 3, 2];

一、并集(A∪B)

js
//方法一:
+;
+// 虽然 NaN 和 NaN 不相等,但是在 Set 集合里面只会存在一个
+// undefined 和 Infinity 在 Set 集合里面也只会存在一个
+let a = [1, 2, 3, NaN];
+let b = [2, 4, 5, NaN];
+const union  =  (arr1,arr2) => [...new Set([...arr1, ...arr2])]// [1, 2, 3, NaN, 4, 5]
+
+//方法二:
+const union = (arr1,arr2) =>  Array.from(new Set(arr1.concat(arr2)))
+
+//先b筛选a中没有的,再连接数组
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val => !arr1.includes(val)))
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val=> arr2.indexOf(val) === -1));
//方法一:
+;
+// 虽然 NaN 和 NaN 不相等,但是在 Set 集合里面只会存在一个
+// undefined 和 Infinity 在 Set 集合里面也只会存在一个
+let a = [1, 2, 3, NaN];
+let b = [2, 4, 5, NaN];
+const union  =  (arr1,arr2) => [...new Set([...arr1, ...arr2])]// [1, 2, 3, NaN, 4, 5]
+
+//方法二:
+const union = (arr1,arr2) =>  Array.from(new Set(arr1.concat(arr2)))
+
+//先b筛选a中没有的,再连接数组
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val => !arr1.includes(val)))
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val=> arr2.indexOf(val) === -1));

二、交集(A∩B)

js
let intersection  = (arr1,arr2) => [...new Set(arr1.filter(val => arr2.includes(val)))];//[2, NaN]
let intersection  = (arr1,arr2) => [...new Set(arr1.filter(val => arr2.includes(val)))];//[2, NaN]

三、差集(A-B)

js
// 差集(a 相对于 b 的差集) 属于a不属于b的元素
+let difference  = (arr1,arr2) => [...new Set(arr1.filter(val => !arr2.includes(val)))];
+ 
+//返回a与b数组区别的集合(交集取反) 
+let a = [1, 2, 3];
+let b = [2, 4, 5];
+let difference = a.concat(b).filter(v => !a.includes(v) || !b.includes(v));
+let difference = a.concat(b).filter(v => !(a.includes(v) && b.includes(v)));
+console.log(difference)// [1,3,4,5]
+
+//方法二:先转为 Set
+let aSet = new Set(a);
+let bSet = new Set(b)
+//  
+let difference = Array.from(new Set(a.concat(b).filter(v => !aSet.has(v) || !bSet.has(v))));
+console.log(difference) // [1,3,4,5]
// 差集(a 相对于 b 的差集) 属于a不属于b的元素
+let difference  = (arr1,arr2) => [...new Set(arr1.filter(val => !arr2.includes(val)))];
+ 
+//返回a与b数组区别的集合(交集取反) 
+let a = [1, 2, 3];
+let b = [2, 4, 5];
+let difference = a.concat(b).filter(v => !a.includes(v) || !b.includes(v));
+let difference = a.concat(b).filter(v => !(a.includes(v) && b.includes(v)));
+console.log(difference)// [1,3,4,5]
+
+//方法二:先转为 Set
+let aSet = new Set(a);
+let bSet = new Set(b)
+//  
+let difference = Array.from(new Set(a.concat(b).filter(v => !aSet.has(v) || !bSet.has(v))));
+console.log(difference) // [1,3,4,5]

对象数组

示例数组

js
let a=[
+    {id:'01',name:'product01'},
+    {id:'02',name:'product02'},
+    {id:'03',name:'product03'},
+    {id:'04',name:'product04'},
+    {id:'05',name:'product05'}
+    ];
+let b=[
+    {id:'03',name:'product03'},
+    {id:'06',name:'product06'},
+    {id:'07',name:'product07'},
+    {id:'08',name:'product08'},
+
+];
let a=[
+    {id:'01',name:'product01'},
+    {id:'02',name:'product02'},
+    {id:'03',name:'product03'},
+    {id:'04',name:'product04'},
+    {id:'05',name:'product05'}
+    ];
+let b=[
+    {id:'03',name:'product03'},
+    {id:'06',name:'product06'},
+    {id:'07',name:'product07'},
+    {id:'08',name:'product08'},
+
+];

一、并集(A∪B)

js
// 用额外对象记录当前项 id 相同的是否收集,此 id 未收集,则进行收集
+//写法一:
+const union = (arr1,arr2) =>{
+    let obj = {};
+    let arr = arr1.concat(arr2);
+   return arr.reduce( (pre,cur) => {
+        if(!obj[cur.id]){
+            pre.push(cur)
+            obj[cur.id] = true
+        }
+        return pre
+    },[])
+}
+
+//写法二:
+const union = (arr1,arr2)=>{
+  let arr = arr1.concat(arr2)
+  let res = []
+  for(let i = 0; i < arr.length; i++){
+    if(res.findIndex(item => item.id === arr[i].id)===-1){
+      res.push(c[i])
+    }
+  }
+  return res
+}
+  //简化
+  //判断目标在数组中相同的 id 是否存在
+const isExist = (arr,target,attr) => arr.findIndex(item => item[attr] == target[attr]) != -1 
+//合并数组并遍历,判断新数组不存在当前项,则收集
+const union = (arr1,arr2) =>  arr1.concat(arr2).reduce((pre,cur) => isExist(pre,cur,'id') ? pre  : [...pre,cur],[])
// 用额外对象记录当前项 id 相同的是否收集,此 id 未收集,则进行收集
+//写法一:
+const union = (arr1,arr2) =>{
+    let obj = {};
+    let arr = arr1.concat(arr2);
+   return arr.reduce( (pre,cur) => {
+        if(!obj[cur.id]){
+            pre.push(cur)
+            obj[cur.id] = true
+        }
+        return pre
+    },[])
+}
+
+//写法二:
+const union = (arr1,arr2)=>{
+  let arr = arr1.concat(arr2)
+  let res = []
+  for(let i = 0; i < arr.length; i++){
+    if(res.findIndex(item => item.id === arr[i].id)===-1){
+      res.push(c[i])
+    }
+  }
+  return res
+}
+  //简化
+  //判断目标在数组中相同的 id 是否存在
+const isExist = (arr,target,attr) => arr.findIndex(item => item[attr] == target[attr]) != -1 
+//合并数组并遍历,判断新数组不存在当前项,则收集
+const union = (arr1,arr2) =>  arr1.concat(arr2).reduce((pre,cur) => isExist(pre,cur,'id') ? pre  : [...pre,cur],[])

二、交集(A∩B)

js
//方法一:
+const intersection = (arr1,arr2) => {
+    const aids = a.map(item => item.id)
+    return arr2.filter(item => aids.includes(item.id))
+}
+//方法二:
+const intersection = (arr1,arr2) =>  arr1.reduce((pre,cur) => arr2.findIndex(item => item.id == cur.id) != -1 ? [...pre,cur] : pre,[])
//方法一:
+const intersection = (arr1,arr2) => {
+    const aids = a.map(item => item.id)
+    return arr2.filter(item => aids.includes(item.id))
+}
+//方法二:
+const intersection = (arr1,arr2) =>  arr1.reduce((pre,cur) => arr2.findIndex(item => item.id == cur.id) != -1 ? [...pre,cur] : pre,[])

三、差集(A-B)

js
//找出arr1数组中,arr2数组没有的对象
+ const diff = (arr1, arr2) =>  arr1.filter(i => arr2.every(j => i.id !== j.id))
+ const diff = (arr1, arr2) =>  arr1.filter(i => !arr2.some(j => i.id === j.id))
//找出arr1数组中,arr2数组没有的对象
+ const diff = (arr1, arr2) =>  arr1.filter(i => arr2.every(j => i.id !== j.id))
+ const diff = (arr1, arr2) =>  arr1.filter(i => !arr2.some(j => i.id === j.id))
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.html" "b/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.html" new file mode 100644 index 00000000..9fe7e0dd --- /dev/null +++ "b/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.html" @@ -0,0 +1,201 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Blob与 File

js
const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })
const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })

ArrayBuffer

js

+
+const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })
+
+//ArrayBuffer
+const blobArrayBuffer = await blob.arrayBuffer()
+const fileArrayBuffer = await file.arrayBuffer()
+
+console.log('[ blobArrayBuffer ]-6', blobArrayBuffer)
+console.log('[ fileArrayBuffer ]-8', fileArrayBuffer)

+
+const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })
+
+//ArrayBuffer
+const blobArrayBuffer = await blob.arrayBuffer()
+const fileArrayBuffer = await file.arrayBuffer()
+
+console.log('[ blobArrayBuffer ]-6', blobArrayBuffer)
+console.log('[ fileArrayBuffer ]-8', fileArrayBuffer)

FileReader

js
const fileReader = new FileReader()
+fileReader.readAsArrayBuffer(file)
+fileReader.onload = (e) => {
+  console.log('[ e ]-13', e)
+  console.log('[ e.target ]-14', e.target)
+  console.log('[ e.target.result ]-15', e.target?.result  )
+  console.log( e.target?.result === fileArrayBuffer) // false
+}
const fileReader = new FileReader()
+fileReader.readAsArrayBuffer(file)
+fileReader.onload = (e) => {
+  console.log('[ e ]-13', e)
+  console.log('[ e.target ]-14', e.target)
+  console.log('[ e.target.result ]-15', e.target?.result  )
+  console.log( e.target?.result === fileArrayBuffer) // false
+}

2023-02-11-18-18-03

DataView

js
const dataView = new DataView(blobArrayBuffer)
+console.log('[ dataView ]-19', dataView)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
+dataView.setUint8(0, 4)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
const dataView = new DataView(blobArrayBuffer)
+console.log('[ dataView ]-19', dataView)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
+dataView.setUint8(0, 4)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))

2023-02-11-18-25-32

FilePicker

js
const openFilePicker = async (e: any) => {
+   const option = {
+     title: 'Open File',
+     accept: {
+      'image/*': ['.png', '.jpg', '.jpeg'],
+     },
+   }
+    const [fileHandle] = await (window as any).showOpenFilePicker(option)
+    const file = await fileHandle.getFile()
+    const fileReader = new FileReader()
+    fileReader.readAsArrayBuffer(file)
+    fileReader.onload = (e) => {
+      console.log('[ e ]-11', e.target?.result)
+    }
+}
const openFilePicker = async (e: any) => {
+   const option = {
+     title: 'Open File',
+     accept: {
+      'image/*': ['.png', '.jpg', '.jpeg'],
+     },
+   }
+    const [fileHandle] = await (window as any).showOpenFilePicker(option)
+    const file = await fileHandle.getFile()
+    const fileReader = new FileReader()
+    fileReader.readAsArrayBuffer(file)
+    fileReader.onload = (e) => {
+      console.log('[ e ]-11', e.target?.result)
+    }
+}

文件操作

ts

+const textarea = ref('Hello World')
+const fh = ref(null)
+//创建文件
+const openCreate = async () => {
+  const  fileHandle  =  await  (window as any).showSaveFilePicker()
+  const fileSteam = await fileHandle.createWritable()
+  await fileSteam.write(textarea.value)
+  await fileSteam.close()
+}
+//打开文件
+const openShow = async () => {
+  const [ fileHandle ] =  await  (window as any).showOpenFilePicker(option)
+  fh.value = fileHandle
+  const file =  await  fileHandle.getFile()
+  textarea.value = await file.text()
+}
+//保存文件
+const openSave = async () => {
+  if(fh.value){
+    const fileSteam = await fh.value.createWritable()
+    await fileSteam.write(textarea.value)
+    await fileSteam.close()
+  }
+}
+//保存为文件
+const openSaveAs = () => {
+  openCreate()
+}

+const textarea = ref('Hello World')
+const fh = ref(null)
+//创建文件
+const openCreate = async () => {
+  const  fileHandle  =  await  (window as any).showSaveFilePicker()
+  const fileSteam = await fileHandle.createWritable()
+  await fileSteam.write(textarea.value)
+  await fileSteam.close()
+}
+//打开文件
+const openShow = async () => {
+  const [ fileHandle ] =  await  (window as any).showOpenFilePicker(option)
+  fh.value = fileHandle
+  const file =  await  fileHandle.getFile()
+  textarea.value = await file.text()
+}
+//保存文件
+const openSave = async () => {
+  if(fh.value){
+    const fileSteam = await fh.value.createWritable()
+    await fileSteam.write(textarea.value)
+    await fileSteam.close()
+  }
+}
+//保存为文件
+const openSaveAs = () => {
+  openCreate()
+}

filepicker

URL

js
//Blob URL
+URL.createObjectURL(blob) 
+
+//Data  URL
+FileReader.readAsDataURL(file)  
+canvas.toDataURL()
//Blob URL
+URL.createObjectURL(blob) 
+
+//Data  URL
+FileReader.readAsDataURL(file)  
+canvas.toDataURL()
vue
<a :href="url">   </a> 
+<img :src="url" />
+<iframe :src="url"></iframe>
<a :href="url">   </a> 
+<img :src="url" />
+<iframe :src="url"></iframe>
ts
type TYPE = 'text' | 'image' | ''
+const url = ref<string>('')
+const onFetch = async (type: TYPE, path: string) => {
+  const response = await fetch(path)
+  //BLOB URL
+  // const data = await response.blob()
+  // url.value = URL.createObjectURL(data)
+
+  //Data URL
+  const fr = new FileReader()
+  fr.onload = (e) => {
+    url.value = e.target?.result as string
+  }
+  fr.readAsDataURL(await response.blob())
+}
type TYPE = 'text' | 'image' | ''
+const url = ref<string>('')
+const onFetch = async (type: TYPE, path: string) => {
+  const response = await fetch(path)
+  //BLOB URL
+  // const data = await response.blob()
+  // url.value = URL.createObjectURL(data)
+
+  //Data URL
+  const fr = new FileReader()
+  fr.onload = (e) => {
+    url.value = e.target?.result as string
+  }
+  fr.readAsDataURL(await response.blob())
+}

参考资料

MDN Blob API 参考
MDN File API 参考
谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64

+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" "b/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" new file mode 100644 index 00000000..d5635db2 --- /dev/null +++ "b/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" @@ -0,0 +1,267 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

资料参考:LearnRegex

应用场景

  1. 表单校验
  2. 字符串匹配和替换、解析(vue模板解析)

可视化工具:

  1. Regulex
  2. Regexper

1. 或者 |

javascript
let tel = "020-99999999"
+console.log(/(010|020)\-\d{8}/.test(tel));//true
let tel = "020-99999999"
+console.log(/(010|020)\-\d{8}/.test(tel));//true

2. 原子表[]、原子组()

javascript
//原子表
+let reg = /[123456]/ //出现在其中就匹配成功
+console.log(reg.test("2")) //true
+console.log(reg.test("9")) //false
+
+//[()] [.+] 特殊符号放在原子表里就是普通符号(保留字符本意)
+let str = 'www.baidu.com+'
+console.log(str.match(/[.+]/gi)) //['.', '.', '+']
+
+//原子组
+let reg = /(34|56)/
+console.log(reg.test("hdjfaks34fjj")) //true 满足组合才行
+console.log(reg.test("hdjfaks35fjj")) //false
//原子表
+let reg = /[123456]/ //出现在其中就匹配成功
+console.log(reg.test("2")) //true
+console.log(reg.test("9")) //false
+
+//[()] [.+] 特殊符号放在原子表里就是普通符号(保留字符本意)
+let str = 'www.baidu.com+'
+console.log(str.match(/[.+]/gi)) //['.', '.', '+']
+
+//原子组
+let reg = /(34|56)/
+console.log(reg.test("hdjfaks34fjj")) //true 满足组合才行
+console.log(reg.test("hdjfaks35fjj")) //false

3. 边界符^$

javascript
let tel = "12020-99999999"
+console.log(/^(010|020)\-\d{8}/.test(tel));//false 以010开头
+
+let tel = "020-999999998"
+console.log(/^(010|020)\-\d{8}$/.test(tel));//false 以8位数结尾
let tel = "12020-99999999"
+console.log(/^(010|020)\-\d{8}/.test(tel));//false 以010开头
+
+let tel = "020-999999998"
+console.log(/^(010|020)\-\d{8}$/.test(tel));//false 以8位数结尾

4. 元字符

image.png

5. 匹配所有字符

javascript
/[\s\S]/  
+/[\d\D]/
/[\s\S]/  
+/[\d\D]/

6. 模式修正符号ig

javascript
let hd = 'djfkdjakDJFKJD'
+hd.match(/[a-z]/ig)
+//i 不区分大小写
+//g 全局匹配
+//m 每一行单独处理(^,$)检测字符串的开头或结尾,如果想要它在每行的开头和结尾生效,则用m
+//u 宽字节匹配
+//y 匹配完不匹配后面(提升效率)
+//字符属性
+let hdstr = `dfa2332,hello! 正则表达式,哈!`
+hdstr.match(/\p{sc=Han}/gu) //按语言系统匹配中文 ['正', '则', '表', '达', '式',  '哈']
+hdstr.match(/\p{P}/gu) //匹配所有标点符号  //[',', '!', ',', '!']
+hdstr.match(/\p{L}/gu) //匹配所有字母
let hd = 'djfkdjakDJFKJD'
+hd.match(/[a-z]/ig)
+//i 不区分大小写
+//g 全局匹配
+//m 每一行单独处理(^,$)检测字符串的开头或结尾,如果想要它在每行的开头和结尾生效,则用m
+//u 宽字节匹配
+//y 匹配完不匹配后面(提升效率)
+//字符属性
+let hdstr = `dfa2332,hello! 正则表达式,哈!`
+hdstr.match(/\p{sc=Han}/gu) //按语言系统匹配中文 ['正', '则', '表', '达', '式',  '哈']
+hdstr.match(/\p{P}/gu) //匹配所有标点符号  //[',', '!', ',', '!']
+hdstr.match(/\p{L}/gu) //匹配所有字母

7. 原子组中的原子表([-\/])

javascript
let dateStr = '2022-08-30'   '2022/08/30'//true 
+let reg = /^\d{4}([-\/])\d{2}\1\d{2}/
+console.log(reg.test('2022-08/30') //false
+
+let reg1 = /^[a-z]\w{3,7}$/gi //校验用户名
+
+
+let hhtml = `<h1>www.baidu.com</h1>
+<h2>www.sougou.com</h2>`
+let reg = /<(h[1-6])>([\s\S]*)<\/\1>/i;
+[
+    "<h1>www.baidu.com</h1>", //匹配到的第一个
+    "h1", //原子组1   
+    "www.baidu.com" //原子组2
+]
+
+//替换操作
+let res = hhtml.replace(reg,`<p>$1</p>`)
+let res = hhtml.replace(reg,(p0,p1,p2)=>`<p>${p1}</p>`
+                        
+$& //找到内容本身 (\0)
+$` //内容前面的字符
+$' //内容后面的字符
+
+let reg = /<(h[1-6])>([\s\S]*)<\/\1>/gi; //全局匹配
+[
+    "<h1>www.baidu.com</h1>",
+    "<h2>www.sougou.com</h2>"
+]
+
+let mailReg =  /^\w[\w-]+@[\w]([\w-]+.)+(com|cn|cc|net|org)/
+
+
+//不记录分组(?:) 原子组中使用?:则(match,exec输出结果中)不会记录此原子组
let dateStr = '2022-08-30'   '2022/08/30'//true 
+let reg = /^\d{4}([-\/])\d{2}\1\d{2}/
+console.log(reg.test('2022-08/30') //false
+
+let reg1 = /^[a-z]\w{3,7}$/gi //校验用户名
+
+
+let hhtml = `<h1>www.baidu.com</h1>
+<h2>www.sougou.com</h2>`
+let reg = /<(h[1-6])>([\s\S]*)<\/\1>/i;
+[
+    "<h1>www.baidu.com</h1>", //匹配到的第一个
+    "h1", //原子组1   
+    "www.baidu.com" //原子组2
+]
+
+//替换操作
+let res = hhtml.replace(reg,`<p>$1</p>`)
+let res = hhtml.replace(reg,(p0,p1,p2)=>`<p>${p1}</p>`
+                        
+$& //找到内容本身 (\0)
+$` //内容前面的字符
+$' //内容后面的字符
+
+let reg = /<(h[1-6])>([\s\S]*)<\/\1>/gi; //全局匹配
+[
+    "<h1>www.baidu.com</h1>",
+    "<h2>www.sougou.com</h2>"
+]
+
+let mailReg =  /^\w[\w-]+@[\w]([\w-]+.)+(com|cn|cc|net|org)/
+
+
+//不记录分组(?:) 原子组中使用?:则(match,exec输出结果中)不会记录此原子组

8.贪婪匹配+*?

javascript
+ //一个或多个
+* //0个或多个
+? //0个或1个
+{0,10} //0-10个
+
+//禁止贪婪(往少的一方倾斜)
++? //一个 let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+*? //匹配到一个就停止let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+?? // let reg = /(.??at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['fat']
+{3,}?  {3,10}? //3个
+
+  //案例练习
+let html= `<span>www.baidu.com</span>
+<span>www.map.baidu.com</span>
+<span>www.know.baidu.com</span>`
+let regbaidu = /<span>[\s\S]+<\/span>/ //贪婪到最后
+let regbaidu1 = /<span>([\s\S]+?)<\/span>/gi
+let newhtml= html.replace(regbaidu1,(v,p1)=> `<h2 style='color:red'>${p1}</h2>`)
+//"<h2 style='color:red'>www.baidu.com</h2>\n<h2 style='color:red'>www.map.baidu.com</h2>\n<h2 style='color:red'>www.know.baidu.com</h2>"
+ //一个或多个
+* //0个或多个
+? //0个或1个
+{0,10} //0-10个
+
+//禁止贪婪(往少的一方倾斜)
++? //一个 let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+*? //匹配到一个就停止let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+?? // let reg = /(.??at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['fat']
+{3,}?  {3,10}? //3个
+
+  //案例练习
+let html= `<span>www.baidu.com</span>
+<span>www.map.baidu.com</span>
+<span>www.know.baidu.com</span>`
+let regbaidu = /<span>[\s\S]+<\/span>/ //贪婪到最后
+let regbaidu1 = /<span>([\s\S]+?)<\/span>/gi
+let newhtml= html.replace(regbaidu1,(v,p1)=> `<h2 style='color:red'>${p1}</h2>`)
+//"<h2 style='color:red'>www.baidu.com</h2>\n<h2 style='color:red'>www.map.baidu.com</h2>\n<h2 style='color:red'>www.know.baidu.com</h2>"

批量验证密码

javascript
let psdRegs = [/^[0-9a-z]{6,10}$/i,/[A-Z]/,/[0-9]/]
+let result = psdRegs.every(reg => reg.test('fdkafad')) //false
+let result = psdRegs.every(reg => reg.test('1f12aA'))  //true
let psdRegs = [/^[0-9a-z]{6,10}$/i,/[A-Z]/,/[0-9]/]
+let result = psdRegs.every(reg => reg.test('fdkafad')) //false
+let result = psdRegs.every(reg => reg.test('1f12aA'))  //true

9. matchAll

javascript
let hstr = `<h1>www.baidu.com</h1>
+<h2>www.map.baidu.com</h2>
+<h3>百度一下</h3>`
+let breg = /<(h[1-6])>([\S\s]+)<\/\1>/gi
+
+hstr.match(breg) //全局匹配拿不到它每个原子组
+['<h1>www.baidu.com</h1>', '<h2>www.map.baidu.com</h2>', '<h3>百度一下</h3>']
+
+//解决方法:使用matchAll
+for(it of hstr.matchAll(breg)){ 
+  console.dir(it);
+  content.push(it[2]);
+}
+//每个匹配项信息
+[
+    "<h1>www.baidu.com</h1>",
+    "h1",  //原子组1
+    "www.baidu.com" //原子组2
+]
let hstr = `<h1>www.baidu.com</h1>
+<h2>www.map.baidu.com</h2>
+<h3>百度一下</h3>`
+let breg = /<(h[1-6])>([\S\s]+)<\/\1>/gi
+
+hstr.match(breg) //全局匹配拿不到它每个原子组
+['<h1>www.baidu.com</h1>', '<h2>www.map.baidu.com</h2>', '<h3>百度一下</h3>']
+
+//解决方法:使用matchAll
+for(it of hstr.matchAll(breg)){ 
+  console.dir(it);
+  content.push(it[2]);
+}
+//每个匹配项信息
+[
+    "<h1>www.baidu.com</h1>",
+    "h1",  //原子组1
+    "www.baidu.com" //原子组2
+]

image.png

10. 断言匹配``

javascript
let reg = /百度(?=地图)/g
+// 只有百度后面有地图两字的才满足要求
+let htm = <p>百度一下,百度地图</p>
+p.innerHTML.replace(reg,`<a href="www.map.baidu.com">$&</a>`)
+
+?= //判断 
+
+?<= //判断前面内容是..
+?<=href= //前面是href="www.baidu.com"符合
+
+?! //限制不是..
+let reg =  /[a-z]+(?!\d)$/i  //限制最后一位不是数字
+
+?! //限定不包含关键词,必须以字母结束
+let reg = /^(?!.*百度.*)[a-z]{4,5}$/i
+
+?<! //前面不是数字 
+let reg = /(?<!\d+)[a-z]+/i
+'baidu88baidu'.match(reg) //baidu
let reg = /百度(?=地图)/g
+// 只有百度后面有地图两字的才满足要求
+let htm = <p>百度一下,百度地图</p>
+p.innerHTML.replace(reg,`<a href="www.map.baidu.com">$&</a>`)
+
+?= //判断 
+
+?<= //判断前面内容是..
+?<=href= //前面是href="www.baidu.com"符合
+
+?! //限制不是..
+let reg =  /[a-z]+(?!\d)$/i  //限制最后一位不是数字
+
+?! //限定不包含关键词,必须以字母结束
+let reg = /^(?!.*百度.*)[a-z]{4,5}$/i
+
+?<! //前面不是数字 
+let reg = /(?<!\d+)[a-z]+/i
+'baidu88baidu'.match(reg) //baidu

将链接替换为想要的网址

image.png

将不含oss的替换

image.png

模糊电话后四位

image.png

案例练习

替换练习

image.png

给原子组起别名

image.png

+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.html" "b/FrontEnd/JavaScript/\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.html" new file mode 100644 index 00000000..d8e205a9 --- /dev/null +++ "b/FrontEnd/JavaScript/\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.html" @@ -0,0 +1,119 @@ + + + + + + 获取目录结构(纯前端) | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

获取目录结构(纯前端)

vue
 <button @click="onSelectDir" class="select-btn">选择文件夹</button>
 <button @click="onSelectDir" class="select-btn">选择文件夹</button>
js
const onSelectDir = async () => {
+  const dirHandle = await window.showDirectoryPicker()
+  await getDirData(dirHandle, directoryData)
+}
+/*递归获取文件夹下的所有文件, 并生成树状结构 
+ {
+"id": "o6ukw45e",
+"name": "core",
+"ftype": "dir",
+"children": [
+  {
+    "id": "bc41wb16",
+    "name": ".eslintrc.cjs",
+    "ftype": "cjs"
+  },]
+}
+*/
+let exclude = ["node_modules", ".git", ".vscode", ".prettierignore", "dist"]; //排除的文件夹
+const getDirData = async (dirHandle, dirData) => {
+  for await (const entry of dirHandle.values()) {
+    let { name, kind } = entry
+    //文件大小
+    if (kind === 'file') {
+      const size = await entry.getFile().then(file => file.size || 0)
+      const ftype = name.split('.').length > 1 ? name.split('.')[1] : 'unknown'
+      dirData.children.push({
+        id: randomId(),
+        name,
+        size,
+        value: size,
+        ftype
+      })
+    } else if (kind === 'directory') {
+      if (exclude.includes(name)) continue;
+      const children = {
+        id: randomId(),
+        name,
+        ftype: 'dir',
+        children: []
+      }
+      dirData.children.push(children)
+      await getDirData(entry, children)
+    }
+  }
+}
const onSelectDir = async () => {
+  const dirHandle = await window.showDirectoryPicker()
+  await getDirData(dirHandle, directoryData)
+}
+/*递归获取文件夹下的所有文件, 并生成树状结构 
+ {
+"id": "o6ukw45e",
+"name": "core",
+"ftype": "dir",
+"children": [
+  {
+    "id": "bc41wb16",
+    "name": ".eslintrc.cjs",
+    "ftype": "cjs"
+  },]
+}
+*/
+let exclude = ["node_modules", ".git", ".vscode", ".prettierignore", "dist"]; //排除的文件夹
+const getDirData = async (dirHandle, dirData) => {
+  for await (const entry of dirHandle.values()) {
+    let { name, kind } = entry
+    //文件大小
+    if (kind === 'file') {
+      const size = await entry.getFile().then(file => file.size || 0)
+      const ftype = name.split('.').length > 1 ? name.split('.')[1] : 'unknown'
+      dirData.children.push({
+        id: randomId(),
+        name,
+        size,
+        value: size,
+        ftype
+      })
+    } else if (kind === 'directory') {
+      if (exclude.includes(name)) continue;
+      const children = {
+        id: randomId(),
+        name,
+        ftype: 'dir',
+        children: []
+      }
+      dirData.children.push(children)
+      await getDirData(entry, children)
+    }
+  }
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/JavaScript/\351\253\230\351\230\266\345\207\275\346\225\260.html" "b/FrontEnd/JavaScript/\351\253\230\351\230\266\345\207\275\346\225\260.html" new file mode 100644 index 00000000..89dad3ad --- /dev/null +++ "b/FrontEnd/JavaScript/\351\253\230\351\230\266\345\207\275\346\225\260.html" @@ -0,0 +1,323 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

高阶函数之filter

定义

  • 通过提供函数实现的依次测试的所有元素,true 则表示通过,如果为 false 则失败。
  • 返回值是一个新数组,由通过测试为 true 的所有元素组成
  • 如果没有任何数组元素通过测试,则返回空数组。

TIP

  1. 原始数组不发生改变
  2. 不会对空数组进行检测
  3. 满足条件的留下,是对原数组的过滤。

语法

js
array.filter(function(currentValue,index,arr), thisValue)
+//currentValue  必须,遍历到的当前元素值
+//index         可选,当前元素的索引值
+//arr           可选,当前元素属于的数组对象
array.filter(function(currentValue,index,arr), thisValue)
+//currentValue  必须,遍历到的当前元素值
+//index         可选,当前元素的索引值
+//arr           可选,当前元素属于的数组对象

用法

过滤小于 100
javascript
const nums = [20,30,110,60,190,50]
+let newNums =nums.filter(n =>{
+  return n < 100
+})
+console.log(newNums)//[20,30,60,50]
const nums = [20,30,110,60,190,50]
+let newNums =nums.filter(n =>{
+  return n < 100
+})
+console.log(newNums)//[20,30,60,50]
返回奇数元素
js
var arr=[1,2,3,4,5,6];
+let res = arr.filter(function(x){
+    return x%2!==0;
+})
+console.log(res)//[1,3,5]
var arr=[1,2,3,4,5,6];
+let res = arr.filter(function(x){
+    return x%2!==0;
+})
+console.log(res)//[1,3,5]
数组去重
js
var  arr= ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
+
+//去除重复元素依靠的是indexOf总是返回第一个元素的位置,
+//后续的重复元素位置与indexOf返回的位置相等,表示是同一个元素
+//后续的重复元素位置与indexOf返回的位置不相等,表示元素重复并且过滤。
+var filterArr = arr.filter((value,index,arr) => arr.indexOf(value)===index;)
+console.log(filterArr);//["apple", "strawberry", "banana", "pear", "orange"]
var  arr= ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
+
+//去除重复元素依靠的是indexOf总是返回第一个元素的位置,
+//后续的重复元素位置与indexOf返回的位置相等,表示是同一个元素
+//后续的重复元素位置与indexOf返回的位置不相等,表示元素重复并且过滤。
+var filterArr = arr.filter((value,index,arr) => arr.indexOf(value)===index;)
+console.log(filterArr);//["apple", "strawberry", "banana", "pear", "orange"]
js
const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
+const arr2 = arr1.filter( (element, index, self) => {
+    return self.indexOf( element ) === index;
+});
+
+console.log( arr2 );
+// [1, 2, 3, 5, 4]
+console.log( arr1 );
+// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]
const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
+const arr2 = arr1.filter( (element, index, self) => {
+    return self.indexOf( element ) === index;
+});
+
+console.log( arr2 );
+// [1, 2, 3, 5, 4]
+console.log( arr1 );
+// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]
找出素数
js
//除了1和自身,不能被其他数整除的
+var arr=[1,2,3,4,5,6,7,8,9,11,20,37];
+const result = arr.filter(value => {
+	if(value == 1) return false;
+ 	if(value == 2) return true; 
+    for(var i = 2; i < Math.sqrt(value) + 1; i++){
+      if(value % i == 0)  return false;
+    }
+     return true;
+ });
//除了1和自身,不能被其他数整除的
+var arr=[1,2,3,4,5,6,7,8,9,11,20,37];
+const result = arr.filter(value => {
+	if(value == 1) return false;
+ 	if(value == 2) return true; 
+    for(var i = 2; i < Math.sqrt(value) + 1; i++){
+      if(value % i == 0)  return false;
+    }
+     return true;
+ });

高阶函数之map

定义

原数组中的每个元素依次调用一个指定方法后,

返回值组成的新数组

TIP

  1. 原始数组不发生改变
  2. 不会对空数组进行检测
  3. 对原数组的加工,返回加工后新数组

语法

js
array.map(function(currentValue,index,arr), thisValue)
+//currentValue  数组中正在处理的当前元素。
+//index可选  数组中正在处理的当前元素的索引。
+//array可选  map 方法被调用的数组。
+//thisArg可选 执行 callback 函数时使用的this 值。
array.map(function(currentValue,index,arr), thisValue)
+//currentValue  数组中正在处理的当前元素。
+//index可选  数组中正在处理的当前元素的索引。
+//array可选  map 方法被调用的数组。
+//thisArg可选 执行 callback 函数时使用的this 值。

用法

返回数组元素平方后的新数组
js
function pow(x){  //定义一个平方函数
+    return x*x;
+}
+
+var arr=[1,2,3,4,5,6,7,8,9];
+var result = arr.map(pow);  //map()传入的是函数对象本身
+console.log(result);       //结果:[1,4,9,16,25,36,49,64,81];
function pow(x){  //定义一个平方函数
+    return x*x;
+}
+
+var arr=[1,2,3,4,5,6,7,8,9];
+var result = arr.map(pow);  //map()传入的是函数对象本身
+console.log(result);       //结果:[1,4,9,16,25,36,49,64,81];
用给定函数创建新字符串
js
const mapString = (str, fn) =>
+  str
+    .split('')
+    .map((c, i) => fn(c, i, str))
+    .join('');
+mapString('lorem ipsum', c => c.toUpperCase()); // 'LOREM IPSUM'
const mapString = (str, fn) =>
+  str
+    .split('')
+    .map((c, i) => fn(c, i, str))
+    .join('');
+mapString('lorem ipsum', c => c.toUpperCase()); // 'LOREM IPSUM'
把二维数组变字符串
js
const arr = [[1, 2], [3, 4]];
+const str = arr.map(row => row.join(',')).join(';');
+console.log(str); // "1,2;3,4"
const arr = [[1, 2], [3, 4]];
+const str = arr.map(row => row.join(',')).join(';');
+console.log(str); // "1,2;3,4"
数字序列转为数组,删除符号
js
const digitize = n => [...`${Math.abs(n)}`].map(i => parseInt(i));
+digitize(123); // [1, 2, 3]
+digitize(-123); // [1, 2, 3]
const digitize = n => [...`${Math.abs(n)}`].map(i => parseInt(i));
+digitize(123); // [1, 2, 3]
+digitize(-123); // [1, 2, 3]
拿到所有图片的图片名称并以数组形式返回
js
const getImages = (el, includeDuplicates = false) => {
+  const images = [...el.getElementsByTagName('img')]
+  const srcList = images.map(img =>
+    img.getAttribute('src')
+  );
+  return includeDuplicates ? srcList : [...new Set(srcList)];
+};
+
+getImages(document, true); 
+// ['image1.jpg', 'image2.png', 'image1.png', '...']
+getImages(document, false);
+// ['image1.jpg', 'image2.png', '...'] 名字去重
const getImages = (el, includeDuplicates = false) => {
+  const images = [...el.getElementsByTagName('img')]
+  const srcList = images.map(img =>
+    img.getAttribute('src')
+  );
+  return includeDuplicates ? srcList : [...new Set(srcList)];
+};
+
+getImages(document, true); 
+// ['image1.jpg', 'image2.png', 'image1.png', '...']
+getImages(document, false);
+// ['image1.jpg', 'image2.png', '...'] 名字去重
vue中循环注册组件
js
Vue.component('ele',{
+		render:function(createElement){
+			return createElement('div',
+			    Array.apply(null,{ length:5 }).map(() => createElement(Child))
+			);
+		}
+	});
Vue.component('ele',{
+		render:function(createElement){
+			return createElement('div',
+			    Array.apply(null,{ length:5 }).map(() => createElement(Child))
+			);
+		}
+	});

高阶函数之 reduce

定义

原始数组不发生改变

对于空数组是不会执行回调函数的

语法

js
arr.reduce(callback , [initialValue])
+//callback (执行数组中每个值的函数,包含四个参数)
+//initialValue (作为第一次调用 callback 的第一个参数。)
+//如果没有提供initialValue,从索引1的地方开始执行callback方法,跳过第一个索引。
+//如果提供initialValue,从索引0开始
arr.reduce(callback , [initialValue])
+//callback (执行数组中每个值的函数,包含四个参数)
+//initialValue (作为第一次调用 callback 的第一个参数。)
+//如果没有提供initialValue,从索引1的地方开始执行callback方法,跳过第一个索引。
+//如果提供initialValue,从索引0开始
js
//执行数组中每个值的callback 函数,包含四个参数
+const sum = arr.reduce(function(previousValue, currentValue, index, array) {
+   return previousValue + currentValue;
+}0)
//执行数组中每个值的callback 函数,包含四个参数
+const sum = arr.reduce(function(previousValue, currentValue, index, array) {
+   return previousValue + currentValue;
+}0)

TIP

1、previousValue :上一次调用回调返回的值,或者是提供的初始值(initialValue)

2、currentValue :数组中当前被处理的元素

3、index :当前元素在数组中的索引

4、array :调用 reduce 函数 的数组

用法

数组求和
js
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
+sum(1, 2, 3, 4); // 10
+sum(...[1, 2, 3, 4]); // 10
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
+sum(1, 2, 3, 4); // 10
+sum(...[1, 2, 3, 4]); // 10
数组去重
js
let arr = [1,2,3,4,4,1]
+let newArr = arr.reduce((pre,cur)=> pre.includes(cur) ? pre : [...pre,cur],[])
+console.log(newArr);// [1, 2, 3, 4]
let arr = [1,2,3,4,4,1]
+let newArr = arr.reduce((pre,cur)=> pre.includes(cur) ? pre : [...pre,cur],[])
+console.log(newArr);// [1, 2, 3, 4]
计算两个或多个数字的平均值
js
const average = (...nums) =>
+  nums.reduce((acc, val) => acc + val, 0) / nums.length;
+average(...[1, 2, 3]); // 2
+average(1, 2, 3); // 2
const average = (...nums) =>
+  nums.reduce((acc, val) => acc + val, 0) / nums.length;
+average(...[1, 2, 3]); // 2
+average(1, 2, 3); // 2
将多维数组转化为一维
js
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
+const convertArr = (arr) => arr.reduce((pre,cur) => Array.isArray(cur) ? [...pre,...convertArr(cur)] : [...pre,cur],[])
+console.log(convertArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
+const convertArr = (arr) => arr.reduce((pre,cur) => Array.isArray(cur) ? [...pre,...convertArr(cur)] : [...pre,cur],[])
+console.log(convertArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
对象里的属性求和
js
var result = [
+    {
+        subject: 'math',
+        score: 10
+    },
+    {
+        subject: 'chinese',
+        score: 20
+    },
+    {
+        subject: 'english',
+        score: 30
+    }
+];
+
+var sum = result.reduce((prev, cur) => cur.score + prev, 0);
+console.log(sum) //60
var result = [
+    {
+        subject: 'math',
+        score: 10
+    },
+    {
+        subject: 'chinese',
+        score: 20
+    },
+    {
+        subject: 'english',
+        score: 30
+    }
+];
+
+var sum = result.reduce((prev, cur) => cur.score + prev, 0);
+console.log(sum) //60
统计数组中每个元素出现的次数
js
arr11 = [111, 22, 111, 234, 999, 999, 111]
+let arr1 = arr11.reduce((pre, item) => {
+    pre[item] = pre[item] ? pre[item] + 1 : 1
+    return pre
+}, {})
+//{ '22': 1, '111': 3, '234': 1, '999': 2 }
arr11 = [111, 22, 111, 234, 999, 999, 111]
+let arr1 = arr11.reduce((pre, item) => {
+    pre[item] = pre[item] ? pre[item] + 1 : 1
+    return pre
+}, {})
+//{ '22': 1, '111': 3, '234': 1, '999': 2 }
js
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
+
+let nameNum = names.reduce((pre,cur)=>{
+  if(cur in pre){
+    pre[cur]++
+  }else{
+    pre[cur] = 1 
+  }
+  return pre
+},{})
+console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
+
+let nameNum = names.reduce((pre,cur)=>{
+  if(cur in pre){
+    pre[cur]++
+  }else{
+    pre[cur] = 1 
+  }
+  return pre
+},{})
+console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}

高阶函数之 sort

定义

sort() 方法用原地算法对数组的元素进行排序,并返回数组,

该排序方法会在原数组上直接进行排序,并不会生成一个排好序的新数组

排序算法现在是稳定的。默认排序顺序是根据字符串 Unicode 码点。

语法

js
arr.sort(sortby)
+//sort() 在没有参数时,返回的结果是按升序来排列的
+
+//sortby	可选。规定排序顺序。必须是函数。
arr.sort(sortby)
+//sort() 在没有参数时,返回的结果是按升序来排列的
+
+//sortby	可选。规定排序顺序。必须是函数。

TIP

function(a, b)(return a- b)

  • 如果指明了参数:compare (a, b) ,(a, b 是两个要比较的元素,a 在 b 前面)那么数组会按照该函数的返回值排序
  • 如果 compare (a, b) 返回值 < 0 ,a 会被排列到 b 之前,即参数 a, b 的顺序保存原样;
  • 如果 compare (a, b) 返回值 = 0 ,a 和 b 的相对位置不变。(ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守)
  • 如果 compare (a, b) 返回值 > 0 ,b 会被排列到 a 之前。即交换参数 a, b 的顺序

用法

js
let sortby= function (a, b) {
+    return a - b;
+}
+let koala=[10, 20, 1, 2].sort(sortby)
+
+console.log(koala);
+// [1 , 2 , 10 , 20]
let sortby= function (a, b) {
+    return a - b;
+}
+let koala=[10, 20, 1, 2].sort(sortby)
+
+console.log(koala);
+// [1 , 2 , 10 , 20]
js
var arr = [10, 20, 1, 2];
+    arr.sort(function (x, y) {
+        if (x < y) {
+            return -1;
+        }
+        if (x > y) {
+            return 1;
+        }
+        return 0;
+    });
+console.log(arr); // [1, 2, 10, 20]
var arr = [10, 20, 1, 2];
+    arr.sort(function (x, y) {
+        if (x < y) {
+            return -1;
+        }
+        if (x > y) {
+            return 1;
+        }
+        return 0;
+    });
+console.log(arr); // [1, 2, 10, 20]

自定义高阶函数

字符串数组每项长度、并转换为整数数组

语法

  • 创建了一个高阶函数 mapForEach ,它接受一个数组和一个回调函数 fn。
  • 它循环遍历传入的数组,并在每次迭代时在 newArray.push 方法调用回调函数 fn 。
  • 回调函数 fn 接收数组的当前元素并返回该元素的长度,该元素存储在 newArray 中。
  • for 循环完成后,newArray 被返回并赋值给 lenArray。

用法

js
const strArray=['JavaScript','PHP','JAVA','C','Python'];
+function mapForEach(arr,fn){
+    const newArray = [];
+    for(let i = 0; i < arr.length;i++){
+        newArray.push(fn(arr[i]));
+    }
+    return newArray;
+}
+const lenArray = mapForEach(strArray,(str) =>  str.length);
+
+console.log(lenArray);//[10,3,4,1,6]
const strArray=['JavaScript','PHP','JAVA','C','Python'];
+function mapForEach(arr,fn){
+    const newArray = [];
+    for(let i = 0; i < arr.length;i++){
+        newArray.push(fn(arr[i]));
+    }
+    return newArray;
+}
+const lenArray = mapForEach(strArray,(str) =>  str.length);
+
+console.log(lenArray);//[10,3,4,1,6]
+ + + + \ No newline at end of file diff --git "a/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.html" "b/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.html" new file mode 100644 index 00000000..8fe4a838 --- /dev/null +++ "b/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.html" @@ -0,0 +1,177 @@ + + + + + + 自动部署 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

自动部署

脚本

sh
#!/usr/bin/env sh
+
+set -e
+
+npm run docs:build
+
+cd docs/.vitepress/dist
+
+git init 
+
+git add -A
+
+git commit -m '🎉deploy gh-pages🎉'
+
+git push -f git@github.com:fxzer/zerdocs.git master:gh-pages
+
+cd ..
+
+rm -rf  dist
+
+cd -
#!/usr/bin/env sh
+
+set -e
+
+npm run docs:build
+
+cd docs/.vitepress/dist
+
+git init 
+
+git add -A
+
+git commit -m '🎉deploy gh-pages🎉'
+
+git push -f git@github.com:fxzer/zerdocs.git master:gh-pages
+
+cd ..
+
+rm -rf  dist
+
+cd -

Action

主要流程

检查代码(Checkout) ===> 启动node环境(Setup Node) ===> 构建静态文件(Build) ===> 把静态文件push到gh-pages,触发gh-pages自带的workflow部署(Push To GitHub Pages)===> 把仓库同步到Gitee(Sync to Gitee) ===> 触发Gitee Pages服务部署(Build Gitee Pages)

yml

+name: Deploy GitHub Pages And Sync to Gitee
+
+# 触发条件:在 push 到 master 分支后
+on:
+  push:
+    branches:
+      - master
+# 任务
+jobs:
+  build-and-deploy:
+    runs-on: ubuntu-latest #部署运行环境搭建
+    steps:
+      - name: Checkout 🛎️
+        uses: actions/checkout@main
+        with:
+          persist-credentials: false
+          fetch-depth: 0 #github代码拉取深度
+      - name: Setup Node  🎬
+        uses: actions/setup-node@main
+        with:
+          node-version: "lts/*"
+      - name: Build 🔧 
+        run: |
+          yarn
+          yarn run build
+          ls -lrth
+      - name: 📲 Push To GitHub Pages
+        uses: ftnext/action-push-ghpages@v1.0.0
+        with:
+          build_dir: dist
+          github_token: ${{ secrets.DEPLOY_TOKEN }}
+      - name: 🔁 Sync to Gitee #同步到Gitee
+        uses: wearerequired/git-mirror-action@master
+        env:
+          # 注意在此项目的 Settings->Actions-> Secrets 配置 GITEE_RSA_PRIVATE_KEY
+          SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }}
+        with:
+          # 注意替换为你的 GitHub 源仓库地址
+          source-repo: 'git@github.com:fxzer/zerdocs.git'
+          # 注意替换为你的 Gitee 目标仓库地址
+          destination-repo: 'git@gitee.com:fxzer/zerdocs.git'
+      - name: ✅ Build Gitee Pages #触发Gitee自动部署
+        uses: yanglbme/gitee-pages-action@master
+        with:
+          # 注意替换为你的 Gitee 用户名
+          gitee-username: fxzer
+          # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
+          gitee-password: ${{ secrets.GITEE_PASSWORD }}
+          # 注意替换为你的 Gitee 仓库 
+          # 坑点:https://gitee.com/fxzer/zerdocs -->则填:fxzer/zerdocs,注意仓库名和路径名不一致问题
+          gitee-repo: fxzer/zerdocs 
+          # 要部署的分支
+          branch: gh-pages

+name: Deploy GitHub Pages And Sync to Gitee
+
+# 触发条件:在 push 到 master 分支后
+on:
+  push:
+    branches:
+      - master
+# 任务
+jobs:
+  build-and-deploy:
+    runs-on: ubuntu-latest #部署运行环境搭建
+    steps:
+      - name: Checkout 🛎️
+        uses: actions/checkout@main
+        with:
+          persist-credentials: false
+          fetch-depth: 0 #github代码拉取深度
+      - name: Setup Node  🎬
+        uses: actions/setup-node@main
+        with:
+          node-version: "lts/*"
+      - name: Build 🔧 
+        run: |
+          yarn
+          yarn run build
+          ls -lrth
+      - name: 📲 Push To GitHub Pages
+        uses: ftnext/action-push-ghpages@v1.0.0
+        with:
+          build_dir: dist
+          github_token: ${{ secrets.DEPLOY_TOKEN }}
+      - name: 🔁 Sync to Gitee #同步到Gitee
+        uses: wearerequired/git-mirror-action@master
+        env:
+          # 注意在此项目的 Settings->Actions-> Secrets 配置 GITEE_RSA_PRIVATE_KEY
+          SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }}
+        with:
+          # 注意替换为你的 GitHub 源仓库地址
+          source-repo: 'git@github.com:fxzer/zerdocs.git'
+          # 注意替换为你的 Gitee 目标仓库地址
+          destination-repo: 'git@gitee.com:fxzer/zerdocs.git'
+      - name: ✅ Build Gitee Pages #触发Gitee自动部署
+        uses: yanglbme/gitee-pages-action@master
+        with:
+          # 注意替换为你的 Gitee 用户名
+          gitee-username: fxzer
+          # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
+          gitee-password: ${{ secrets.GITEE_PASSWORD }}
+          # 注意替换为你的 Gitee 仓库 
+          # 坑点:https://gitee.com/fxzer/zerdocs -->则填:fxzer/zerdocs,注意仓库名和路径名不一致问题
+          gitee-repo: fxzer/zerdocs 
+          # 要部署的分支
+          branch: gh-pages
+ + + + \ No newline at end of file diff --git "a/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.html" "b/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.html" new file mode 100644 index 00000000..dd6deb85 --- /dev/null +++ "b/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.html" @@ -0,0 +1,1017 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

基础语法

一、基础类型

JS类型

js
boolean
+number
+string
+array
+object	//对象: {}、 function(){}
+null
+undefined	//默认情况下null和undefined是所有类型的子类型。可以赋值给其他类型
boolean
+number
+string
+array
+object	//对象: {}、 function(){}
+null
+undefined	//默认情况下null和undefined是所有类型的子类型。可以赋值给其他类型

object 类型常见用法

typescript
//1.严格要求
+let b :{name: string ,age: number}
+b = { name:'zhangsan ',age :18}
//1.严格要求
+let b :{name: string ,age: number}
+b = { name:'zhangsan ',age :18}
typescript
//2.可选
+let b :{name: string ,age?: number}
+b = { name:'zhangsna '}
//2.可选
+let b :{name: string ,age?: number}
+b = { name:'zhangsna '}
typescript
//3.多个可选
+let b :{name: string ,[porname:string]:string}
+b = { name:'zhangsna ',address:'上海',gender:''}
//3.多个可选
+let b :{name: string ,[porname:string]:string}
+b = { name:'zhangsna ',address:'上海',gender:''}
typescript
//4.箭头函数设置函数结构
+let d: (c:number,d:number)=>number
+d = function(n1,n2){
+    return n1+n2
+}
//4.箭头函数设置函数结构
+let d: (c:number,d:number)=>number
+d = function(n1,n2){
+    return n1+n2
+}

数组

typescript
let arr: string[] 	//字符串数组 arr = ['zhansan','lisi']
+let arr1:Array<number>	//数值数组 arr1 = [1,2,3,4,5]
let arr: string[] 	//字符串数组 arr = ['zhansan','lisi']
+let arr1:Array<number>	//数值数组 arr1 = [1,2,3,4,5]

元组

typescript
let h: [string ,number]
+h = ['hello', 123]
let h: [string ,number]
+h = ['hello', 123]

枚举

typescript
enum Color {Red = 1, Green = 2, Blue = 4}
+let c: Color = Color.Green;  //c为2
+Color[2] // Green 枚举的值得到它的名字
enum Color {Red = 1, Green = 2, Blue = 4}
+let c: Color = Color.Green;  //c为2
+Color[2] // Green 枚举的值得到它的名字

TS新增类型

typescript
字面量	  //限制类型在几个值之间(联合类型)例:let b : 'male'|'amale' 、 
+enum	//枚举类型
+tuple	//元组 [string, number];
+void	//表示没有返回值,不返回或返回undefined,和其他类型平等关系,不能直接赋值给其他类型	
+Any		//任意类型
+unknown //未知类型 
+never	//永远不返回结果,没有类型是never的子类型、没有类型可以赋值给never类型(除了never本身之外)
+//函数用于执行不到返回值那一步,(抛出异常或死循环)的返回值类型
字面量	  //限制类型在几个值之间(联合类型)例:let b : 'male'|'amale' 、 
+enum	//枚举类型
+tuple	//元组 [string, number];
+void	//表示没有返回值,不返回或返回undefined,和其他类型平等关系,不能直接赋值给其他类型	
+Any		//任意类型
+unknown //未知类型 
+never	//永远不返回结果,没有类型是never的子类型、没有类型可以赋值给never类型(除了never本身之外)
+//函数用于执行不到返回值那一步,(抛出异常或死循环)的返回值类型

unknownany区别

typescript
let a: any
+let b: string 
+b =  a // OK  any类型可以赋值任意类型
let a: any
+let b: string 
+b =  a // OK  any类型可以赋值任意类型
typescript
let e: unknown
+e = 'TypeScript'
+let f: string
+f = e 	//Error 未知类型不能直接赋值给其他变量(类型安全的any)
+
+//处理方式一:
+if(typeof  e === "string" ){
+	f = e
+}
+//处理方式二:类型断言
+f = e as string 
+f = <string> e
let e: unknown
+e = 'TypeScript'
+let f: string
+f = e 	//Error 未知类型不能直接赋值给其他变量(类型安全的any)
+
+//处理方式一:
+if(typeof  e === "string" ){
+	f = e
+}
+//处理方式二:类型断言
+f = e as string 
+f = <string> e

|& :表示或,&:表示且

typescript
let g: string | boolean
+g = 'sdfj'
+g = true
+
+let h :string & number
+let i: {name:string} &{age:number}
+f = {
+    name:'h hh',
+    age:18
+}
let g: string | boolean
+g = 'sdfj'
+g = true
+
+let h :string & number
+let i: {name:string} &{age:number}
+f = {
+    name:'h hh',
+    age:18
+}

二、类型声名

typescript
let name:string	 //声名string类型变量
+let age = 19	 //类型声名可省略,会自动类型推断,age推断为number
let name:string	 //声名string类型变量
+let age = 19	 //类型声名可省略,会自动类型推断,age推断为number

三、as const 断言

typescript
let a = 99 as const 	//a值只能为99,指定明确的值、类型
+let b:string = 'asfghj'
+let obj = {
+    name:b,		//值只能为string
+} as const
let a = 99 as const 	//a值只能为99,指定明确的值、类型
+let b:string = 'asfghj'
+let obj = {
+    name:b,		//值只能为string
+} as const
typescript
let x = 1024
+let y = '2048'
+
+let arr = [x,y] 	// arr[1]类型是 number|string
+let arr = [x,y] as const 	// 指定为元组,arr[1]类型只能为 number
+//同:let arr = <const>[x,y]
let x = 1024
+let y = '2048'
+
+let arr = [x,y] 	// arr[1]类型是 number|string
+let arr = [x,y] as const 	// 指定为元组,arr[1]类型只能为 number
+//同:let arr = <const>[x,y]

面对对象

一、类

typescript
class 类名 {
+    属性名: 类型;
+    
+    constructor(参数: 类型){
+        this.属性名 = 参数;
+    }
+    
+    方法名(){
+        ....
+    }
+
+}
class 类名 {
+    属性名: 类型;
+    
+    constructor(参数: 类型){
+        this.属性名 = 参数;
+    }
+    
+    方法名(){
+        ....
+    }
+
+}

栗子:

typescript
    class Person{
+        name: string;
+        age: number;
+    
+        constructor(name: string, age: number){
+            this.name = name;
+            this.age = age;
+        }
+    
+        sayHello(){
+            console.log(`大家好,我是${this.name}`);
+        }
+    }
    class Person{
+        name: string;
+        age: number;
+    
+        constructor(name: string, age: number){
+            this.name = name;
+            this.age = age;
+        }
+    
+        sayHello(){
+            console.log(`大家好,我是${this.name}`);
+        }
+    }

构造函数

注1:在TS中只能有一个构造器方法!

typescript
class Person{
+    name: string;
+    age: number
+
+    constructor(name: string, age: number) {
+        this.name = name;
+        this.age = age;
+    }
+}
class Person{
+    name: string;
+    age: number
+
+    constructor(name: string, age: number) {
+        this.name = name;
+        this.age = age;
+    }
+}

注2:子类继承父类时,必须调用父类的构造方法(如果子类中也定义了构造方法)!

typescript
class A {
+    protected num: number;
+    constructor(num: number) {
+        this.num = num;
+    }
+}
+
+class X extends A {
+    protected name: string;
+    constructor(num: number, name: string) {
+        super(num);
+        this.name = name;
+    }
+}
class A {
+    protected num: number;
+    constructor(num: number) {
+        this.num = num;
+    }
+}
+
+class X extends A {
+    protected name: string;
+    constructor(num: number, name: string) {
+        super(num);
+        this.name = name;
+    }
+}

二、封装

  • 静态属性(static):

    • 声明为static的属性或方法不再属于实例,而是属于类的属性;
  • 只读属性(readonly):

    • 如果在声明属性时添加一个readonly,则属性便成了只读属性无法修改
  • TS中属性具有三种修饰符:

    • public(默认值),可以在类、子类和对象中修改
    • protected ,可以在类、子类中修改
    • private ,可以在类中修改
public
typescript
class Person{
+    public name: string; // 写或什么都不写都是public
+    public age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以在类中修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(`大家好,我是${this.name}`);
+    }
+}
+
+class Employee extends Person{
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 可以通过对象修改
class Person{
+    public name: string; // 写或什么都不写都是public
+    public age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以在类中修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(`大家好,我是${this.name}`);
+    }
+}
+
+class Employee extends Person{
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 可以通过对象修改
protected
typescript
class Person{
+    protected name: string;
+    protected age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(`大家好,我是${this.name}`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改
class Person{
+    protected name: string;
+    protected age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(`大家好,我是${this.name}`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改
private
typescript
class Person{
+    private name: string;
+    private age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(`大家好,我是${this.name}`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中不能修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改
class Person{
+    private name: string;
+    private age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(`大家好,我是${this.name}`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中不能修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改

三、属性存取器

对于一些不希望被任意修改的属性,可以将其设置为private

直接将其设置为private将导致无法再通过对象修改其中的属性

我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器

读取属性的方法叫做setter方法,设置属性的方法叫做getter方法

示例
typescript
class Person{
+    private _name: string;
+
+    constructor(name: string){
+        this._name = name;
+    }
+
+    get name(){
+        return this._name;
+    }
+
+    set name(name: string){
+        this._name = name;
+    }
+
+}
+
+const p1 = new Person('孙悟空');
+// 实际通过调用getter方法读取name属性
+console.log(p1.name);
+// 实际通过调用setter方法修改name属性 
+p1.name = '猪八戒';
class Person{
+    private _name: string;
+
+    constructor(name: string){
+        this._name = name;
+    }
+
+    get name(){
+        return this._name;
+    }
+
+    set name(name: string){
+        this._name = name;
+    }
+
+}
+
+const p1 = new Person('孙悟空');
+// 实际通过调用getter方法读取name属性
+console.log(p1.name);
+// 实际通过调用setter方法修改name属性 
+p1.name = '猪八戒';

静态属性

静态属性(方法),也称为类属性。使用静态属性无需创建实例,通过类即可直接使用

静态属性(方法)使用static开头

typescript
class Tools{
+    static PI = 3.1415926;
+    
+    static sum(num1: number, num2: number){
+        return num1 + num2
+    }
+}
+
+console.log(Tools.PI);
+console.log(Tools.sum(123, 456));
class Tools{
+    static PI = 3.1415926;
+    
+    static sum(num1: number, num2: number){
+        return num1 + num2
+    }
+}
+
+console.log(Tools.PI);
+console.log(Tools.sum(123, 456));

四、继承

通过继承可以将其他类中的属性和方法引入到当前类中,通过继承可以在不修改类的情况下完成对类的扩展

typescript
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(`${this.name}在汪汪叫!`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(`${this.name}在汪汪叫!`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();

重写

发生继承时,如果子类中的方法会替换掉父类中的同名方法,这就称为方法的重写

typescript
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+
+    run(){
+        console.log(`父类中的run方法!`);
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(`${this.name}在汪汪叫!`);
+    }
+
+    run(){
+        console.log(`子类中的run方法,会重写父类中的run方法!`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+
+    run(){
+        console.log(`父类中的run方法!`);
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(`${this.name}在汪汪叫!`);
+    }
+
+    run(){
+        console.log(`子类中的run方法,会重写父类中的run方法!`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();

五、抽象类(abstract class)

抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例,用于抽取类的共同特点

使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现;

typescript
abstract class Animal{
+  abstract run(): void;
+  bark(){
+      console.log('动物在叫~');
+  }
+}
+
+class Dog extends Animals{
+  run(){
+      console.log('狗在跑~');
+  }
+}
abstract class Animal{
+  abstract run(): void;
+  bark(){
+      console.log('动物在叫~');
+  }
+}
+
+class Dog extends Animals{
+  run(){
+      console.log('狗在跑~');
+  }
+}

六、接口

typescript
//用于类型检查
+interface Person {
+    firstName: string;
+     lastName: string;
+     address?: string;	//可选属性
+ readonly age: number;	//只读属性
+}
+
+function greeter(person: Person) {
+    return "Hello, " + person.firstName + " " + person.lastName;
+}
//用于类型检查
+interface Person {
+    firstName: string;
+     lastName: string;
+     address?: string;	//可选属性
+ readonly age: number;	//只读属性
+}
+
+function greeter(person: Person) {
+    return "Hello, " + person.firstName + " " + person.lastName;
+}

基本配置

一、TS编译配置

但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json

tsconfig.json详细配置
js
{
+/* 
+    tsconfig.json 是ts编译器的配置文件,ts编译器可以更具它的信息来对代码进行编译
+    "include" 用来表示指定哪些ts文件需要被编译
+        路径:
+            *表示任意文件,
+            **表示任意目录
+    "exclude" 用来表示不需要被编译的文件目录
+            默认值:{"node_modules", "bower_components", "jspm_packages"}
+*/
+    "include": [
+        "./src/**/*"
+    ],
+    
+    // "exclude": [
+    //     "./src/hello/**/*"
+    // ]
+     /*
+        被继承的配置文件
+        例如:"extends": "。/configs/base",
+      */
+  //  "extends": "",
+      /*
+        指定被编译文件的列表,只有需要编译的文件少时才会用到
+      */
+    //  "files": [],
+
+    //compilerOptions 编译器的选项 
+    "compilerOptions": {
+        
+        //target 用来指定ts被编译为ES的版本
+        //'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'.
+        "target": "ES2015",
+
+        //module 指定要使用的模块化的规范
+        //'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'
+        "module": "es2015",
+        
+        //lib 用来指定项目所用的库
+       /* 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 
+       'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 
+          'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include',
+          'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 
+         'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 
+         'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', */
+
+
+        //outDir 用来指定编译后文件所在的目录
+        "outDir": "./dist",
+
+        //outFile 将代码合并为一个文件
+        // "outFile": "./dist/app.js",
+
+        // 是否对js文件进行编译,默认是false
+        "allowJs": true,
+
+        // 是否检查js代码是否符合语法规范,默认值是false
+        "checkJs": true,
+
+        // 是否移除注释
+        "removeComments": true,
+
+        // 不生成编译后的文件
+        "noEmit": false,
+
+        // 当有错误时不生成编译文件
+        "noEmitOnError": true,
+
+        // 所有严格检查的总开关
+        "strict": true,
+
+        // 用来设置编译后的文件是否使用严格模式,默认是false
+        // 在ES6中的模块化会自动使用严格模式,而无需在文件开头添加`'use strict'`
+        "alwaysStrict": true,
+
+        // 不允许隐式的any类型
+        "noImplicitAny": true,
+
+        // 不允许不明确类型的this
+        "noImplicitThis": true,
+
+        // 严格检查空值
+        "strictNullChecks": true
+
+
+    }
+}
{
+/* 
+    tsconfig.json 是ts编译器的配置文件,ts编译器可以更具它的信息来对代码进行编译
+    "include" 用来表示指定哪些ts文件需要被编译
+        路径:
+            *表示任意文件,
+            **表示任意目录
+    "exclude" 用来表示不需要被编译的文件目录
+            默认值:{"node_modules", "bower_components", "jspm_packages"}
+*/
+    "include": [
+        "./src/**/*"
+    ],
+    
+    // "exclude": [
+    //     "./src/hello/**/*"
+    // ]
+     /*
+        被继承的配置文件
+        例如:"extends": "。/configs/base",
+      */
+  //  "extends": "",
+      /*
+        指定被编译文件的列表,只有需要编译的文件少时才会用到
+      */
+    //  "files": [],
+
+    //compilerOptions 编译器的选项 
+    "compilerOptions": {
+        
+        //target 用来指定ts被编译为ES的版本
+        //'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'.
+        "target": "ES2015",
+
+        //module 指定要使用的模块化的规范
+        //'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'
+        "module": "es2015",
+        
+        //lib 用来指定项目所用的库
+       /* 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 
+       'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 
+          'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include',
+          'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 
+         'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 
+         'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', */
+
+
+        //outDir 用来指定编译后文件所在的目录
+        "outDir": "./dist",
+
+        //outFile 将代码合并为一个文件
+        // "outFile": "./dist/app.js",
+
+        // 是否对js文件进行编译,默认是false
+        "allowJs": true,
+
+        // 是否检查js代码是否符合语法规范,默认值是false
+        "checkJs": true,
+
+        // 是否移除注释
+        "removeComments": true,
+
+        // 不生成编译后的文件
+        "noEmit": false,
+
+        // 当有错误时不生成编译文件
+        "noEmitOnError": true,
+
+        // 所有严格检查的总开关
+        "strict": true,
+
+        // 用来设置编译后的文件是否使用严格模式,默认是false
+        // 在ES6中的模块化会自动使用严格模式,而无需在文件开头添加`'use strict'`
+        "alwaysStrict": true,
+
+        // 不允许隐式的any类型
+        "noImplicitAny": true,
+
+        // 不允许不明确类型的this
+        "noImplicitThis": true,
+
+        // 严格检查空值
+        "strictNullChecks": true
+
+
+    }
+}

二、webpack整合

步骤如下:

1. 初始化项目

进入项目根目录,执行命令 npm init -y,创建package.json文件

2. 下载构建工具

bash
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin

3. 配置webpack

webpack.config.js详细配置
js
// 引入一个包
+const path = require('path');
+// 引入html插件
+const HTMLWebpackPlugin = require('html-webpack-plugin');
+//引入clean插件
+const { CleanWebpackPlugin } = require('clean-webpack-plugin')
+
+// npm init -y 初始化 创建package.json文件
+// npm i -D webpack webpack-cli typescript ts-loader  安装四个依赖
+// 编写webpack配置文件
+// 编写tsconfig.json文件
+// 修改package.json中加上build命令
+// npm i -D html-webpack-plugin //自动生成html
+// npm i -D webpack-dev-server //自动响应浏览器更新
+// npm i -D clean-webpack-plugin //清楚dist目录旧文件
+
+//webpack 中所有的配置信息都应该写在module.exports中
+module.exports = {
+
+    // 指定入口文件
+    entry: "./src/index.ts",
+
+    // 指定打包文件所在目录
+    output: {
+        //指定打包文件的目录
+        path: path.resolve(__dirname, 'dist'),
+        //打包后文件的名字
+        filename: "bundle.js",
+        //告诉webpack不使用箭头函数
+        environment: {
+            arrowFunction: false
+        }
+
+    },
+    //指定webpack打包时要使用的模块
+    module: {
+        // 指定要loader加载的规则
+        rules: [
+            {
+                // test指定的时规则生效的文件
+                test: /\.ts$/,//以ts结尾的文件
+                // 要使用的loader
+                use: [
+                    // 配置babel
+                    {
+                        //指定加载器
+                        loader: "babel-loader",
+                        // 设置babel
+                        options: {
+                            //设置预定义的环境
+                            presets: [
+                                [
+                                    //指定环境的插件
+                                    "@babel/preset-env",
+                                    // 配置信息
+                                    {
+                                        // 要兼容的目标浏览器及版本
+                                        targets: {
+                                            "chrome": "58",
+                                            "ie": "11"
+                                        },
+                                        //指定corejs的版本
+                                        "corejs": "3",
+                                        //使用corejs的方式 "usage"  表示按需加载
+                                        "useBuiltIns": "usage" 
+                                    }
+
+                                ]
+                            ]
+                        }
+                    },
+                    // 'babel-loader',
+                    'ts-loader'
+                ],
+                // 要排除的文件
+                exclude: /node-modules/
+            }
+        ]
+    },
+
+    //配置Webpack 插件
+    plugins: [
+        new CleanWebpackPlugin(),
+        new HTMLWebpackPlugin({
+            // title: "这是一个自定义的title"、
+            template: "./src/index.html" 
+        }),
+    ],
+
+    // 用来设置引用模块,可以将这些文件识别为模块
+    resolve: {
+        extensions: ['.ts', '.js']
+    }
+}
// 引入一个包
+const path = require('path');
+// 引入html插件
+const HTMLWebpackPlugin = require('html-webpack-plugin');
+//引入clean插件
+const { CleanWebpackPlugin } = require('clean-webpack-plugin')
+
+// npm init -y 初始化 创建package.json文件
+// npm i -D webpack webpack-cli typescript ts-loader  安装四个依赖
+// 编写webpack配置文件
+// 编写tsconfig.json文件
+// 修改package.json中加上build命令
+// npm i -D html-webpack-plugin //自动生成html
+// npm i -D webpack-dev-server //自动响应浏览器更新
+// npm i -D clean-webpack-plugin //清楚dist目录旧文件
+
+//webpack 中所有的配置信息都应该写在module.exports中
+module.exports = {
+
+    // 指定入口文件
+    entry: "./src/index.ts",
+
+    // 指定打包文件所在目录
+    output: {
+        //指定打包文件的目录
+        path: path.resolve(__dirname, 'dist'),
+        //打包后文件的名字
+        filename: "bundle.js",
+        //告诉webpack不使用箭头函数
+        environment: {
+            arrowFunction: false
+        }
+
+    },
+    //指定webpack打包时要使用的模块
+    module: {
+        // 指定要loader加载的规则
+        rules: [
+            {
+                // test指定的时规则生效的文件
+                test: /\.ts$/,//以ts结尾的文件
+                // 要使用的loader
+                use: [
+                    // 配置babel
+                    {
+                        //指定加载器
+                        loader: "babel-loader",
+                        // 设置babel
+                        options: {
+                            //设置预定义的环境
+                            presets: [
+                                [
+                                    //指定环境的插件
+                                    "@babel/preset-env",
+                                    // 配置信息
+                                    {
+                                        // 要兼容的目标浏览器及版本
+                                        targets: {
+                                            "chrome": "58",
+                                            "ie": "11"
+                                        },
+                                        //指定corejs的版本
+                                        "corejs": "3",
+                                        //使用corejs的方式 "usage"  表示按需加载
+                                        "useBuiltIns": "usage" 
+                                    }
+
+                                ]
+                            ]
+                        }
+                    },
+                    // 'babel-loader',
+                    'ts-loader'
+                ],
+                // 要排除的文件
+                exclude: /node-modules/
+            }
+        ]
+    },
+
+    //配置Webpack 插件
+    plugins: [
+        new CleanWebpackPlugin(),
+        new HTMLWebpackPlugin({
+            // title: "这是一个自定义的title"、
+            template: "./src/index.html" 
+        }),
+    ],
+
+    // 用来设置引用模块,可以将这些文件识别为模块
+    resolve: {
+        extensions: ['.ts', '.js']
+    }
+}

4.配置TS编译选项

json
{
+   "compilerOptions": {
+       "target": "ES2015",
+       "module": "ES2015",
+       "strict": true
+   }
+}
{
+   "compilerOptions": {
+       "target": "ES2015",
+       "module": "ES2015",
+       "strict": true
+   }
+}

5 .修改package.json配置

typescript
{
+   ...
+   "scripts": {
+       "test": "echo \"Error: no test specified\" && exit 1",
+       "build": "webpack",
+       "start": "webpack serve --open chrome.exe" //使用chrome启动
+   },
+   ...
+}
{
+   ...
+   "scripts": {
+       "test": "echo \"Error: no test specified\" && exit 1",
+       "build": "webpack",
+       "start": "webpack serve --open chrome.exe" //使用chrome启动
+   },
+   ...
+}

6.项目使用

在src下创建ts文件,并在并命令行执行npm run build对代码进行编译;

或者执行npm start来启动开发服务器;

7.Babel

Babel作用

虽然TS在编译时也支持代码转换,但是只支持简单的代码转换;

对于例如:Promise等ES6特性,TS无法直接转换,这时还要用到babel来做转换;

7.1 安装依赖包:

npm i -D @babel/core @babel/preset-env babel-loader core-js

共安装了4个包,分别是:

  • @babel/core:babel的核心工具
  • @babel/preset-env:babel的预定义环境
  • @babel-loader:babel在webpack中的加载器
  • core-js:core-js用来使老版本的浏览器支持新版ES语法

7.2 修改webpack.config.js配置文件

js
...
+module: {
+    rules: [
+        {
+            test: /\.ts$/,
+            use: [
+                {
+                    loader: "babel-loader",
+                    options:{
+                        presets: [
+                            [
+                                "@babel/preset-env",
+                                {	//支持的目标版本
+                                    "targets":{
+                                        "chrome": "58", 
+                                        "ie": "11"
+                                    },
+                                    //corejs版本
+                                    "corejs":"3",
+                                    "useBuiltIns": "usage"
+                                }
+                            ]
+                        ]
+                    }
+                },
+                {
+                    loader: "ts-loader",
+
+                }
+            ],
+            exclude: /node_modules/
+        }
+    ]
+}
+...
...
+module: {
+    rules: [
+        {
+            test: /\.ts$/,
+            use: [
+                {
+                    loader: "babel-loader",
+                    options:{
+                        presets: [
+                            [
+                                "@babel/preset-env",
+                                {	//支持的目标版本
+                                    "targets":{
+                                        "chrome": "58", 
+                                        "ie": "11"
+                                    },
+                                    //corejs版本
+                                    "corejs":"3",
+                                    "useBuiltIns": "usage"
+                                }
+                            ]
+                        ]
+                    }
+                },
+                {
+                    loader: "ts-loader",
+
+                }
+            ],
+            exclude: /node_modules/
+        }
+    ]
+}
+...
+ + + + \ No newline at end of file diff --git "a/FrontEnd/TypeScript/\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.html" "b/FrontEnd/TypeScript/\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.html" new file mode 100644 index 00000000..53272956 --- /dev/null +++ "b/FrontEnd/TypeScript/\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.html" @@ -0,0 +1,83 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

松散类型自动推推导

ts
//1.
+type Size = "sm" | "xs"
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs"
+}
+
+// 2.
+type Size = "sm" | "xs" | string
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,但模版中使用失去类型提示
+}
+
+//3.
+type Size = "sm" | "xs" | Omit<string,"sm" | "xs">
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
+
+//4.封装为 type
+type Size = LooseAutoComplete<"sm" | "xs">
+type LooseAutoComplete<T extends string> = T | Omit<string, T>
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
//1.
+type Size = "sm" | "xs"
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs"
+}
+
+// 2.
+type Size = "sm" | "xs" | string
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,但模版中使用失去类型提示
+}
+
+//3.
+type Size = "sm" | "xs" | Omit<string,"sm" | "xs">
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
+
+//4.封装为 type
+type Size = LooseAutoComplete<"sm" | "xs">
+type LooseAutoComplete<T extends string> = T | Omit<string, T>
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
+ + + + \ No newline at end of file diff --git "a/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.html" "b/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.html" new file mode 100644 index 00000000..39605b18 --- /dev/null +++ "b/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.html" @@ -0,0 +1,295 @@ + + + + + + Typescript 配置文件(tsconfig.json)解析 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Typescript 配置文件(tsconfig.json)解析

TypeScript带来的类型系统以及强大的IDE支持,让前端开发也变得严谨而流畅。但TypeScript不是原生的Javascript代码,需要进行编译才能转换为Javascript代码。

tsconfig.json是编译TypeScript的配置文件,对书写TypeScript代码十分重要。因为有些选项如果你没配置,则需要严格按照TypeScript的规则来书写,对初期使用TypeScript的同学而言,稍不留神就会书写出不符合规则的代码,从而导致编译报错,打击自信心。其实早期可以通过关闭一些规则设置,从而更愉快的从js转为ts开发。笔者根据项目实战经历来解释一些常用的编译选项,文末也会附上笔者整理的所有tsconfig.json选项的解释。

1. experimentalDecorators

是否启用实验性的ES装饰器。boolean类型,默认值:false。官方解释(opens new window)

TypeScript和ES6中引入了Class的概念,同时在stage 2 proposal (opens new window)提出了Java等服务器端语言早就有的装饰器模式。通过引入装饰器模式,能极大简化书写代码,把一些通用逻辑封装到装饰器中。很多库都有用到该特性,比如vue-class-component 及 vuex-class等库。当你使用这些库时,必须开启experimentalDecorators

ts
function f() {
+    console.log("f(): evaluated");
+    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
+        console.log("f(): called");
+    }
+}
+
+class C {
+    @f()
+    method() {}
+}
function f() {
+    console.log("f(): evaluated");
+    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
+        console.log("f(): called");
+    }
+}
+
+class C {
+    @f()
+    method() {}
+}

启用 vuex-class同时需要设置strictFunctionTypes选项为false

2. strictPropertyInitialization

是否类的非undefined属性已经在构造函数里初始化。 boolean类型,默认值:false

直白点,就是所有的属性值,都需要赋有初始值。建议把strictPropertyInitialization设置为false,这样就不需要定义一个变量就必须赋有初始值。对使用vuex-class库的同学,建议请把这个值设为false,绝对能省很多事。

ts
export default class Home extend Vue{
+    jobId: string // 如果开启strictPropertyInitialization,则这里会报错,因为没有赋值默认值
+
+    method1() :void {
+        console.log(this.jobId)
+    }
+}
export default class Home extend Vue{
+    jobId: string // 如果开启strictPropertyInitialization,则这里会报错,因为没有赋值默认值
+
+    method1() :void {
+        console.log(this.jobId)
+    }
+}

如果设置该选项为true,需要同时启用--strictNullChecks或启用--strict

3. noImplicitAny

有隐含的 any类型时是否报错。boolean值,默认值:false

ts是有默认推导的,同时还有any类型,所以不是每个变量或参数定义需要明确告知类型是什么。如果开启该值,当有隐含any类型时,会报错。建议初次上手TypeScript,把该选项设置为false。

ts
// 当开启noImplicitAny时,需要隐含当any需要明确指出
+arr.find(item => item.name === name) // error
+arr.find((item: any) => item.name === name) // ok
// 当开启noImplicitAny时,需要隐含当any需要明确指出
+arr.find(item => item.name === name) // error
+arr.find((item: any) => item.name === name) // ok

4. target

指定编译的ECMAScript目标版本。枚举值:"ES3", "ES5", "ES6"/ "ES2015", "ES2016", "ES2017","ESNext"。默认值: “ES3”

TypeScript是ES6的超集,所以你可以使用ES6来编写ts代码(通常我们也的确这么做)。然而,当编译ts代码时,可以把ts转为ES5或更早的js代码。所以需要选择一个编译的目标版本。vue-cli3的typescript模板,设置为“ESNext”,因为现代大部分应用项目都会使用Webpack(Parcel也很棒)进行打包,Webpack会把你的代码转换成在所有浏览器中可运行的代码。

target: "ESNext" 是指tc39最新的ES proposed features(opens new window)

5. module

指定生成哪个模块系统代码。枚举值:"None", "CommonJS", "AMD", "System", "UMD", "ES6", "ES2015","ESNext"。默认值根据--target选项不同而不同,当target设置为ES6时,默认module为“ES6”,否则为“commonjs”

通常使用ES6的模块来写ts代码,然而2016年1月以前,基本上没有浏览器原生支持ES6的模块系统,所以需要转换为不同的模块系统,如:CommonJS、AMD、SystemJS等,而module选项就是指定编译使用对应的模块系统。

6. lib

编译过程中需要引入的库文件的列表。string[]类型,可选的值有很多,常用的有ES5,ES6,ESNext,DOM,DOM.Iterable、WebWorker、ScriptHost等。该值默认值是根据--target选项不同而不同。当target为ES5时,默认值为['DOM ', 'ES5', 'ScriptHost'];当target为ES6时,默认值为['DOM', 'ES6', 'DOM.Iterable', 'ScriptHost']

为了在ts代码中使用ES6中的类,比如Array.form、Set、Reflect等,需要设置lib选项,在编译过程中把这些标准库引入。这样在编译过程中,如果遇到属于这些标准库的class或api时,ts编译器不会报错。

7. moduleResolution

决定如何处理模块。string类型,“node”或者“classic”,默认值:“classic”。官方解释(opens new window)

说直白点,也就是遇到import { AAA } from './aaa'该如何去找对应文件模块解析。对于工程项目,笔者建议大家使用node(vue-cli3 ts模板默认设置为node策略),因为这个更符合平时我们的书写习惯以及认知(平时都是webpack打包,webpack又基于node之上)。

text
// 在源文件/root/src/A.ts中import { b } from "./moduleB"
+// 两种解析方式查找文件方式不同
+
+// classic模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.d.ts
+
+// node模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.tsx
+3. /root/src/moduleB.d.ts
+4. /root/src/moduleB/package.json (if it specifies a "types" property)
+5. /root/src/moduleB/index.ts
+6. /root/src/moduleB/index.tsx
+7. /root/src/moduleB/index.d.ts
// 在源文件/root/src/A.ts中import { b } from "./moduleB"
+// 两种解析方式查找文件方式不同
+
+// classic模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.d.ts
+
+// node模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.tsx
+3. /root/src/moduleB.d.ts
+4. /root/src/moduleB/package.json (if it specifies a "types" property)
+5. /root/src/moduleB/index.ts
+6. /root/src/moduleB/index.tsx
+7. /root/src/moduleB/index.d.ts

8. paths

模块名或路径映射的列表。Object值

这是一个非常有用的选项,比如我们经常使用'@/util/help'来代替'./src/util/help',省的每次在不同层级文件import模块时,都纠结于是'./'还是'../'。该选项告诉编译器遇到匹配的值时,去映射的路径下加载模块。

ts
{
+    "baseUrl": ".", // 注意:baseUrl不可少
+    "paths": {
+      // 映射列表
+      "@/*": [
+        "src/*"
+      ],
+      "moduleA": [
+        "src/libs/moduleA"
+      ]
+    }
+}
+
+// in ts code
+import Setting from '@/components/Setting.vue' // 模块实际位置: src/components/Setting.vue
+import TestModule from 'moduleA/index.js' // 模块实际位置: src/libs/moduleA/index.js
{
+    "baseUrl": ".", // 注意:baseUrl不可少
+    "paths": {
+      // 映射列表
+      "@/*": [
+        "src/*"
+      ],
+      "moduleA": [
+        "src/libs/moduleA"
+      ]
+    }
+}
+
+// in ts code
+import Setting from '@/components/Setting.vue' // 模块实际位置: src/components/Setting.vue
+import TestModule from 'moduleA/index.js' // 模块实际位置: src/libs/moduleA/index.js

9. strictNullChecks

是否启用严格的 null检查模式。boolean值,默认值:false

未处理的null和undefined经常会导致BUG的产生,所以TypeScript包含了strictNullChecks选项来帮助我们减少对这种情况的担忧。当启用了strictNullChecks,null和undefined获得了它们自己各自的类型null和undefined。开启该模式有助于发现并处理可能为undefined的赋值。如果是正式项目,笔者建议开启该选项;如果只是练手TypeScirpt,可以关闭该选项,不然所有可能为null/undefined的赋值,都需要写联合类型。

ts
// 未开启strictNullChecks,number类型包含了null和undefined类型
+let foo: number = 123;
+foo = null; // Okay
+foo = undefined; // Okay
+
+// 开启strictNullChecks
+let foo: string[] | undefined = arr.find(key => key === 'test')
+// foo.push('1') // error - 'foo' is possibly 'undefined'
+foo && foo.push('1') // okay
// 未开启strictNullChecks,number类型包含了null和undefined类型
+let foo: number = 123;
+foo = null; // Okay
+foo = undefined; // Okay
+
+// 开启strictNullChecks
+let foo: string[] | undefined = arr.find(key => key === 'test')
+// foo.push('1') // error - 'foo' is possibly 'undefined'
+foo && foo.push('1') // okay

注意:启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks, --strictFunctionTypes和--strictPropertyInitialization

10. noUnusedLocals

有未使用的变量时,是否抛出错误。boolean值,默认值: false

顾名思义,当发现变量定义但没有使用时,编译不报错。eslint的rule中也有该条,建议正式项目将该选项开启,设置为true,使得代码干净整洁。

11. noUnusedParameters

有未使用的参数时,是否抛出错误。boolean值,默认值: false

建议正式项目开启该选项,设置为true,理由同上。

12. allowJs

是否允许编译javascript文件。boolean值,默认值:false

如果设置为true,js后缀的文件也会被typescript进行编译。

13. typeRoots和types

默认所有可见的"@types"包会在编译过程中被包含进来。如果指定了typeRoots,只有typeRoots下面的包才会被包含进来。如果指定了types,只有被列出来的npm包才会被包含进来。详细内容可看此处(opens new window)

可以指定"types": []来禁用自动引入@types包

14. files、include和exclude

编译文件包含哪些文件以及排除哪些文件

未设置include时,编译器默认包含当前目录和子目录下所有的TypeScript文件(.ts, .d.ts 和 .tsx)。如果allowJs被设置成true,JS文件(.js和.jsx)也被包含进来。exclude排除那些不需要编译的文件或文件夹。

ts
{
+    "compilerOptions": {},
+    "include": [
+        "src/**/*"
+    ],
+    "exclude": [
+        "node_modules",
+        "**/*.spec.ts"
+    ]
+}
{
+    "compilerOptions": {},
+    "include": [
+        "src/**/*"
+    ],
+    "exclude": [
+        "node_modules",
+        "**/*.spec.ts"
+    ]
+}

tsconfig.json全解析

json
{
+  "compilerOptions": {
+    /* 基本选项 */
+    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'("ESNext"表示最新的ES语法,包括还处在stage X阶段)
+    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
+    "lib": [],                             // 指定要包含在编译中的库文件
+    "allowJs": true,                       // 允许编译 javascript 文件
+    "checkJs": true,                       // 报告 javascript 文件中的错误
+    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
+    "declaration": true,                   // 生成相应的 '.d.ts' 文件
+    "sourceMap": true,                     // 生成相应的 '.map' 文件
+    "outFile": "./",                       // 将输出文件合并为一个文件
+    "outDir": "./",                        // 指定输出目录
+    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
+    "removeComments": true,                // 删除编译后的所有的注释
+    "noEmit": true,                        // 不生成输出文件
+    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
+    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
+
+    /* 严格的类型检查选项 */
+    "strict": true,                        // 启用所有严格类型检查选项
+    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
+    "strictNullChecks": true,              // 启用严格的 null 检查
+    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
+    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
+
+    /* 额外的检查 */
+    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
+    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
+    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
+    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
+
+    /* 模块解析选项 */
+    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)。默认是classic
+    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
+    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
+    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
+    "typeRoots": [],                       // 包含类型声明的文件列表
+    "types": [],                           // 需要包含的类型声明文件名列表
+    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。
+
+    /* Source Map Options */
+    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
+    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
+    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
+    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
+
+    /* 其他选项 */
+    "experimentalDecorators": true,        // 启用装饰器
+    "emitDecoratorMetadata": true,         // 为装饰器提供元数据的支持
+    "strictFunctionTypes": false           // 禁用函数参数双向协变检查。
+  },
+  /* 指定编译文件或排除指定编译文件 */
+  "include": [
+      "src/**/*"
+  ],
+  "exclude": [
+      "node_modules",
+      "**/*.spec.ts"
+  ],
+  "files": [
+    "core.ts",
+    "sys.ts"
+  ],
+  // 从另一个配置文件里继承配置
+  "extends": "./config/base",
+  // 让IDE在保存文件的时候根据tsconfig.json重新生成文件
+  "compileOnSave": true // 支持这个特性需要Visual Studio 2015, TypeScript1.8.4以上并且安装atom-typescript插件
+}
{
+  "compilerOptions": {
+    /* 基本选项 */
+    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'("ESNext"表示最新的ES语法,包括还处在stage X阶段)
+    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
+    "lib": [],                             // 指定要包含在编译中的库文件
+    "allowJs": true,                       // 允许编译 javascript 文件
+    "checkJs": true,                       // 报告 javascript 文件中的错误
+    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
+    "declaration": true,                   // 生成相应的 '.d.ts' 文件
+    "sourceMap": true,                     // 生成相应的 '.map' 文件
+    "outFile": "./",                       // 将输出文件合并为一个文件
+    "outDir": "./",                        // 指定输出目录
+    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
+    "removeComments": true,                // 删除编译后的所有的注释
+    "noEmit": true,                        // 不生成输出文件
+    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
+    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
+
+    /* 严格的类型检查选项 */
+    "strict": true,                        // 启用所有严格类型检查选项
+    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
+    "strictNullChecks": true,              // 启用严格的 null 检查
+    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
+    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
+
+    /* 额外的检查 */
+    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
+    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
+    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
+    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
+
+    /* 模块解析选项 */
+    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)。默认是classic
+    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
+    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
+    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
+    "typeRoots": [],                       // 包含类型声明的文件列表
+    "types": [],                           // 需要包含的类型声明文件名列表
+    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。
+
+    /* Source Map Options */
+    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
+    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
+    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
+    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
+
+    /* 其他选项 */
+    "experimentalDecorators": true,        // 启用装饰器
+    "emitDecoratorMetadata": true,         // 为装饰器提供元数据的支持
+    "strictFunctionTypes": false           // 禁用函数参数双向协变检查。
+  },
+  /* 指定编译文件或排除指定编译文件 */
+  "include": [
+      "src/**/*"
+  ],
+  "exclude": [
+      "node_modules",
+      "**/*.spec.ts"
+  ],
+  "files": [
+    "core.ts",
+    "sys.ts"
+  ],
+  // 从另一个配置文件里继承配置
+  "extends": "./config/base",
+  // 让IDE在保存文件的时候根据tsconfig.json重新生成文件
+  "compileOnSave": true // 支持这个特性需要Visual Studio 2015, TypeScript1.8.4以上并且安装atom-typescript插件
+}
+ + + + \ No newline at end of file diff --git a/GoodTool/index.html b/GoodTool/index.html new file mode 100644 index 00000000..a16544c1 --- /dev/null +++ b/GoodTool/index.html @@ -0,0 +1,31 @@ + + + + + + 实用工具集锦 | ZerDocs + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Interview/Brower/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" "b/Interview/Brower/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" new file mode 100644 index 00000000..5620e7a9 --- /dev/null +++ "b/Interview/Brower/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" @@ -0,0 +1,31 @@ + + + + + + 事件循环机制 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

事件循环机制

进程与线程

描述

进程是操作系统分配资源的基本单位,线程是操作系统调度的基本单位,线程可以看做轻量级的进程。

  1. 一个进程中至少包含一个线程,线程不能包含进程,不能单独存在,必须由进程启动和管理

  2. 多个进程间不能共享资源,都有自己私有的程序计数器(记录执行指令地址),线程可以共享同一个进程间的资源

  3. 上下文切换:进程慢,线程快(从一个切换到另一个)

  4. 操纵者不同:进程操纵者是操作系统,线程操纵者一般为程序员

image-20230223165307358

浏览器的线程与进程

浏览器是一个多进程多线程的应用程序

  1. 浏览器进程:负责浏览器界面展示、用户交互、子进程管理等;浏览器进程内部会启动多个线程处理不同的任务。
  2. 网络进程:负责加载网络资源,网络进程内部会启动多个线程来处理不同的网络任务。
  3. 渲染进程:渲染进程启动后,会启动一个渲染主进程,主进程负责执行 HTML、CSS、JS 代码。

默认每个标签页开启一个新进程,以保证标签页之间不互相影响。

渲染进程任务

  1. 解析 HTML
  2. 解析 CSS
  3. 计算 样式
  4. 页面布局
  5. 处理图层
  6. 每秒把页面渲染 60 次
  7. 执行全局 JS 代码
  8. 执行事件处理函数
  9. 执行定时器的回调函数

事件循环

2023-03-05-21-01-25

事件循环解释
  1. 在最开始的时候,渲染主线程会进入一个无限循环

  2. 每一次循环会检查消息队列中是否有任务存在。如果有,就取出第一个任务执行,执行完一个后进入下一次循环;如果没有,则进入休眠状态。

  3. 其他所有线程(包括其他进程的线程)可以随时向消息队列添加任务。新任务会加到消息队列的未尾。在添加新任务时,“如果主线程是休眠状态,则会将其唤醒以绁续循环拿取任务;如此循环往复,持续进行。

异步与事件循环理解

单线程是异步产生的原因,事件循环是异步的实现方式。

如何理解异步

Js是一门单线程的语言,这是因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。

而渲染主线程承担渲染页面、执行 JS 等诸多的任务。

如果使用同步的方式,就极有可能导致主线程产生阻塞,从而导致消息队列中的很多其他任务无法得到执行。

这样一来,一方面会导致繁忙的主线程白白的消耗时间,另一方面导致页面无法及时更新,给用户造成卡死现象。

所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时,比如计时器、网络、事件监听,主线程将任务交给其他线程去处理;

自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的未尾排队,等待主线程调度执行。

在这种异步模式下,浏览器永不阻塞,从而最大限度的保证了单线程的流畅运行。使用异步的方式,渲染主线程永不阻塞

消息队列

任务没有优先级,在消息队列中先进先出。但是 消息队列有优先级

每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不同类型的任务可以分属于不同的队列。

在一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行。

浏览器必须准备好一个微队列,微队列中的任务优先所有其他任务执行。

JS 中的计时器能做到精确计时吗

不行,因为有操作系统计时函数偏差、事件循环机制的损耗:

1.计算机硬件没有原子钟,无法做到精确计时

2.操作系统的计时函数本身就有少量偏差! 由于 JS 的计时器最终调用的是操作系统的函数,也就携带了此偏养

3.按照 W3C 的标准,浏览器实现计时器时,如果嵌套层级超过 5 层,间隔时间少于 4 毫秒,则会增加到 4 毫秒 这又带来了偏差

4. 受事件循环的影响,计时器的回调函数只能在主线程空闲时运行,因此又带来了偏差。

2023-03-05-21-56-25

+ + + + \ No newline at end of file diff --git "a/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.html" "b/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.html" new file mode 100644 index 00000000..24ace243 --- /dev/null +++ "b/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.html" @@ -0,0 +1,31 @@ + + + + + + 浏览器网页请求过程 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

浏览器网页请求过程

  1. 网络:请求资源
  2. 渲染:处理渲染

完整的 HTTP 请求过程

域名解析 ==> 与服务器建立连接 ==> 发起 HTTP 请求 ==> 服务器响应 HTTP 请求,浏览器得到 html 代码 ==> 浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片) ==> 浏览器对页面进行渲染呈现给用户

一、域名解析

  1. Chrome 浏览器 会首先搜索浏览器自身的 DNS 缓存,有且没有过期则解析到此结束。
  2. 如果浏览器自身的缓存里面没有找到对应的条目,会搜索操作系统自身的 DNS 缓存,有且没有过期则停止搜索解析到此结束

Windows 系统:ipconfig/displaydns 命令查看

  1. 如果在 Windows 系统的 DNS 缓存也没有找到,则读取 hosts 文件

hosts 位于 ‪C:\Windows\System32\drivers\etc\hosts

  1. hosts 文件中也没有找到对应的条目,浏览器就会发起一个 DNS 的系统调用,就会向本地配置的首选 DNS 服务器发起域名解析请求

    并返回给 Windows 系统内核,内核又把结果返回给浏览器。(这是递归的请求,也就是运营商的 DNS 服务器必须得提供并返回该域名的 IP 地址)

  2. 经过以上的 4 个步骤,还没有解析成功

注:一般会进行以下几步

操作系统就会查找 NetBIOS name Cache == > WINS 服务器 ==> 客户端就要进行广播查找 ==> 客户端就读取 LMHOSTS 文件

如果还没有解析成功,那么就宣告这次解析失败,那就无法跟目标计算机进行通信。只要其中有一步可以解析成功,那就可以成功和目标计算机进行通信。

二、与服务器建立连接

  1. TCP 连接的建立

客户端的请求到达服务器,首先就是三次握手建立 TCP 连接

三次握手的目的:试探一下对方是否遵循 TCP/IP 协议,为了在不可靠的信道上建立起可靠的连接

为什么要进行第三次握手:为了防止服务器端开启一些无用的连接,增加服务器开销;

以及防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

img

三、发起 HTTP 请求

http 协议:计算机通过网络进行通信的规则,是一个基于请求与响应,无状态的,应用层的协议,常基于 TCP/IP 协议传输数据。

请求报文结构

请求报文包括四个部分:请求行,请求头,空行,请求体。

img

四、服务器端响应 HTTP 请求,浏览器得到 HTML 代码

HTTP 的响应报文也由四部分组成:响应行、响应头、空行、响应体

img

报文结构参考

五、浏览器渲染过程

2023-03-05-22-05-19

  1. 解析 html 结构,形成 Dom 树
  2. 解析 CSS,生成 cssom
  3. 将 CSSOM 和 DOM 合并形成 render 树
  4. 计算 layout 布局
  5. 将布局渲染到屏幕上

整个渲染流程分为多个阶段,分别是: HTML 解析、样式计算、布局、分层、绘制、分块、光栅化、画

一、解析 HTML

解析过程中遇到 CSS 解析 CSS,遇到 JS执行 JS。为了提高解析效率,浏览器在开始解析前,会启动一个预解析的线程,率先下载 HTML 中的外部 CSS 文件和外部的JS 文件。

如果主线程解析到 link 位置,此时外部的CSS 文件还没有下载解析好,主线程不会等待,继续解析后续的 HTML。这是因为下载和解析 css 的工作是在预解析线程中进行的。这就是csS 不会阻塞 HTML 解析的根本原因。

如果主线程解析到 script 位置,会停止解析 HTML,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML。这是因为 Js 代码的执行过程可能会修改当前的DOM 树,所以 DOM 树的生成必须暂停。这就是 JS 会阳塞 HTML 解析的根本原因。

第一步完成后,会得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、外部样式、行内样式均会包含在 CSSOM 树中。 2023-03-05-22-07-542023-03-05-22-29-15

解析成对象,提供 JS 可操作的能力

二、解析 CSS

2023-03-05-22-10-48

document.styleSheets、document.styleSheets[0].addRule('div':'border :2px solid red') 可查看、操作浏览器样式表

三、样式计算

主线程会遍历得到的DOM 树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style

在这一过程中,很多预设值会变成绝对值,比如 red 会变成 rgb;相对单位会变成绝对单位,比如 em 会变成 px

这一步完成后,会得到一棵带有样式的DOM 树

2023-03-05-22-31-23

四、布局Layout

DOM树和 Layout 不一定是一一对应的,比如head默认样式display:none,::before在 Layout 树阶段,布局完成后形成布局树。

2023-03-05-22-38-44

五、分层Layer

主线程使用复杂的策略对布局树进行分层。

六、绘制Paint

为每个层生成绘制指令

七、分块Tiling

分块工作交给多个线程同时进行

八、光栅化Raster

合成线程将信息交给 GPU 进程,将每个快变成位图,优先处理靠近视口的块,此过程会用到 GPU 加速,提升运算速率。

九、画Draw

合成线程计算出每个位图在屏幕上的位置,交给 GPU 进行呈现。变形(旋转,缩放,倾斜)等发生在合成线程,与渲染主线程无关,这是 transform 效率高的本质原因。

2023-03-06-21-54-14

回流reflow

2023-03-06-21-56-10

reflow 的本质就是重新计算 layout 树。

当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。

为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 ref1ow 是异步完成的。

也同样因为如此,当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息浏览器在反复权衡下,最终决定获取属性立即 ref1ow。

引起回流属性和方法:任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。

  1. 页面首次渲染
  2. 添加或者删除可见的DOM元素
  3. 元素尺寸或位置发生改变
  4. 元素字体大小变化
  5. 浏览器窗口大小发生改变
  6. 激活CSS伪类(例如::hover)
  7. 查询某些属性或调用某些方法

重绘repaint

repaint 的本质就是重新根据分层信息计算了绘制指令。

当改动了可见样式后,就需要重新计算,会引发 repaint。

由于元素的布局信息也属于可见样式,所以reflow 一定会引起 repaint。

2023-03-06-22-20-02

为什么 transform 的效率高?

因为 transform 既不会影响布局也不会影响绘制指令,它影响的只是渲染流程的最后一个「draw」 阶段由于 draw 阶段在合成线程中;

所以 transform 的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌.也不会影响 transform 的变化。

需要更新属性,只是影响元素的外观、风格,不影响布局。改变 ​color​​​,​ ​background-color​​​, ​​visibility 等属性

参考链接

六、浏览器对页面进行渲染呈现给用户,关闭连接

四次挥手

img

问题一:

为什么连接的时候是三次握手,关闭的时候却是四次握手?

为了保障数据发送完再断开连接

问题二:

为什么要等待一段时间在关闭连接?

因为客户端发送完 ack 包后中途可能丢失,此时服务端未收到 ack 包会重发 fin 包,客户端在发送 ack 包刷新等待时间,

确保服务端关闭再 关闭客户端

参考视频 1

参考视频 2

+ + + + \ No newline at end of file diff --git "a/Interview/Brower/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.html" "b/Interview/Brower/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.html" new file mode 100644 index 00000000..8a866c1d --- /dev/null +++ "b/Interview/Brower/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.html" @@ -0,0 +1,31 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

http与https区别

http:超文本传输协议,明文传输,信息不安全。用的是80端口

https:具有安全性的ssl加密传输协议,信息安全。用的443端口

前端缓存

HTTP缓存

在服务器代码上设置

  1. 强缓存:使用Expires、Cache-Control(优先级高

判断过程: 请求再次发起 -> 浏览器根据 expires 和 cache-control 判断目标资源是否命中"强缓存" -> 若命中,直接从缓存获取资源,不再与服务器发生通讯。

  1. 协商缓存:协商缓存主要有四个头字段,它们两两组合配合使用,当命中协商缓存的时候,服务器会返回HTTP状态码304,让客户端直接 从本地缓存里面读取文件。

浏览器缓存

localStorage、sessionStorage、cookie

+ + + + \ No newline at end of file diff --git "a/Interview/CSS/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" "b/Interview/CSS/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" new file mode 100644 index 00000000..037dc930 --- /dev/null +++ "b/Interview/CSS/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" @@ -0,0 +1,185 @@ + + + + + + CSS基础面试题 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

CSS基础面试题

伪类与伪元素

解释

都不需要添加额外的HTML元素的情况下为文档添加样式和效果。

伪类:开头为单冒号:,伪类是选择器的一种,用于给元素某种状态(滑动、点击等)添加对应的样式,在原本元素上修改

伪元素:开头为双冒号::,用于创建一些不在文档树中的又可以通过 CSS 控制样式的虚拟元素,向元素添加额外的内容或样式。

image-20230227112239445

image-20230227112221284

:nth-child():nth-of-type()

:nth-child(n) :匹配到第 n 个兄弟

:nth-of-type(n):匹配到同类型的第 n 个兄弟元素

水平垂直居中

  1. 行内元素:text-align 与 line-height 块级元素:
  2. flex + margin:auto、grid + margin:auto
css
.parent{
+  display: flex; /* grid */
+}
+.children{
+  margin:auto; 
+}
.parent{
+  display: flex; /* grid */
+}
+.children{
+  margin:auto; 
+}
  1. flex布局
css
.parent{
+  display: flex; 
+  justify-content: center;
+  align-items:center;
+}
.parent{
+  display: flex; 
+  justify-content: center;
+  align-items:center;
+}
  1. grid布局
css
.parent{
+  display: grid; 
+  justify-content: center;
+  align-items:center;/* 网格内项目垂直居中 */
+}
+
+/* 或 */
+
+.box{
+  display: grid;
+  justify-content:center;
+  align-content: center;/* 容器内网格垂直居中 */
+}
.parent{
+  display: grid; 
+  justify-content: center;
+  align-items:center;/* 网格内项目垂直居中 */
+}
+
+/* 或 */
+
+.box{
+  display: grid;
+  justify-content:center;
+  align-content: center;/* 容器内网格垂直居中 */
+}
  1. 绝对定位 + transform
css
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 50%;
+  left:50%;
+  transform: translate(-50%,-50%);   
+}
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 50%;
+  left:50%;
+  transform: translate(-50%,-50%);   
+}
  1. 绝对定位 + margin
css
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 0;
+  left:0;
+  right:0;
+  bottom:0;
+  margin:auto;
+}
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 0;
+  left:0;
+  right:0;
+  bottom:0;
+  margin:auto;
+}

盒模型的理解

当对一个文档进行布局(layout)的时候,浏览器的渲染引擎会根据标准,把每个元素表示为一个矩形的盒子。

盒模型从内到外由 content(内容) + padding(内边距) + border(边框) + margin(外边距) 组成。

默认为W3C 标准盒模型 content-boxbox-sizing:content-box: height = content 。

可以通过box-sizing改变其计算方式,通常改为怪异盒模型box-sizing:border-box: height = content + padding + border 。

这样能够更精确地控制元素的尺寸和定位,元素的宽度和高度可以直接指定为内容区域的尺寸,而无需考虑内边距和边框。

BFC 及其应用

所谓 BFC块格式化上下文),指的是一个独立的布局环境,BFC 内部的元素布局与外部互不影响。

  • 浮动元素(float 值不为 none)
  • 块级元素的 overflow 属性不为 visible,clip
  • 绝对定位的元素 包含 position: fixedposition: absolute
  • display: inline-blockdisplay: table-cellflex,grid

应用

  1. 解决相邻元素外边距塌陷
  2. 清除浮动解决父元素高度塌陷

CSS 选择器

!important权重最高

权重

1000:内联样式

100: id选择器

10:类、伪类、属性选择器

1:标签、伪元素选择器

0:子元素、后代、通配符、相邻选择器

多个可进行累加,相同属性后定义覆盖先定义。

2023-03-18-23-39-34

如何实现动画

  1. 用 CSS @keyframes关键帧
  2. 使用 JS 的 setIntervalrequestAnimationFrame,手动控制元素的位置和样式来实现动画效果

实现渐变背景

  1. 使用 CSS3 渐变,通过 linear-gradientradial-gradient 属性来实现, background: linear-gradient(to right, #ff00cc, #333399)

  2. 使用 SVG 渐变,通过定义一个 <linearGradient><radialGradient> 元素来实现

html
<svg width="100%" height="100%">
+   <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
+     <stop offset="0%" stop-color="#f00"/>
+     <stop offset="100%" stop-color="#00f"/>
+   </linearGradient>
+   <rect x="0" y="0" width="100%" height="100%" fill="url(#gradient)"/>
+ </svg>
<svg width="100%" height="100%">
+   <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
+     <stop offset="0%" stop-color="#f00"/>
+     <stop offset="100%" stop-color="#00f"/>
+   </linearGradient>
+   <rect x="0" y="0" width="100%" height="100%" fill="url(#gradient)"/>
+ </svg>

定位position

静态定位static:默认值,此时 top, right, bottom, leftz-index 属性无效

相对定位relative:保留原来位置进行定位,定位时相对于原来位置进行定位

绝对定位absolute:元素会被移出正常文档流,并不为元素预留空间,相对于最近的非 static 定位祖先元素的偏移,直到 body

固定定位fixed:相对于浏览器视口进行定位,当元素祖先的 transformperspectivefilterbackdrop-filter 属性非 none 时,容器由视口改为该祖先。

黏性定位sticky:相对于最近滚动祖先定位,滚动到元素top小于设定值(top:20px;)则转为固定定位。(relative+fixed)

隐藏元素的方式

image-20230221172950214

用css3实现饼图

css
.pie{
+  width: 500px;
+  height: 500px;
+  border-radius: 50%;
+  /* 画饼图 */
+  background: conic-gradient(
+    red 6deg,
+    orange 6deg 18deg,
+    yellow 18deg 45deg,
+    green 45deg 110deg,
+    blue 110deg 200deg,
+    purple 200deg
+  );
+}
.pie{
+  width: 500px;
+  height: 500px;
+  border-radius: 50%;
+  /* 画饼图 */
+  background: conic-gradient(
+    red 6deg,
+    orange 6deg 18deg,
+    yellow 18deg 45deg,
+    green 45deg 110deg,
+    blue 110deg 200deg,
+    purple 200deg
+  );
+}

margin和padding适用场景

marginPadding
需要在边框留白需要在边框留白
留白处不需要背景色时留白处需要背景色时
上下相连的元素,会相互抵消15px+20px的margin,得到20px的空白上下相连的元素,会累加15px+20px的padding,得到35px的空白

清除margin塌陷 兄弟相邻元素:overflow: hidden、flex 布局

html
 <div class="container">
+      <div class="item">1</div>
+      <!--<div class="wrap">  1.额外包一层并加上 overflow: hidden;-->
+        <div class="item">2</div>
+      <!--</div>-->
+    </div>
 <div class="container">
+      <div class="item">1</div>
+      <!--<div class="wrap">  1.额外包一层并加上 overflow: hidden;-->
+        <div class="item">2</div>
+      <!--</div>-->
+    </div>
css
.container {
+  border: 1px solid #ccc;
+  /* 2.形成 BFC: display: flex; */
+  
+}
+.wrap {
+  overflow: hidden;
+}
+.item {
+  height: 100px;
+  width: 100px;
+  margin: 10px;
+  overflow: hidden;
+  border: 1px solid #ccc;
+}
.container {
+  border: 1px solid #ccc;
+  /* 2.形成 BFC: display: flex; */
+  
+}
+.wrap {
+  overflow: hidden;
+}
+.item {
+  height: 100px;
+  width: 100px;
+  margin: 10px;
+  overflow: hidden;
+  border: 1px solid #ccc;
+}

父子相邻 margin 重叠

(1)给父元素添加透明边框

(2)给父元素添加overflow: hidden;

(3)给父元素添加position: fixed;

(4)给父元素添加display: table/flex/grid;

(5)将子元素都margin改为父元素的padding

可替换元素

在 HTML 中, 是指其内容不受文档流影响,而是由外部资源定义的元素。

这些元素的内容可以通过 CSS 样式或者 JavaScript 来修改,但是本身的标签和属性并不能直接控制其显示效果。

常见的可替换元素包括 img、input、textarea、select、video、audio

Canvas和SVG区别

Canvas和SVG都是用于创建图形的HTML5元素,但它们有着不同的工作原理和适用场景。

Canvas是一种基于位图的绘图技术,它使用JavaScript在HTML5画布中创建像素级别的图形,可以制作出非常复杂的动态效果。Canvas要求开发者掌握像素级别的操作,需要自己编写代码来实现各种绘图功能,因此相对较难掌握。

而SVG是基于矢量图形的绘图技术,它利用XML描述二维图形,并通过浏览器解析渲染出来。由于SVG是基于矢量图形的绘图技术,所以它具有无限放大和缩小不失真的优势。另外,SVG也具有更好的可访问性和SEO性能。

总的来说,如果需要制作交互式和复杂的图形应用程序,Canvas是更好的选择;而如果需要制作高质量的静态图形、图表或图标等,则SVG更适合。

矢量图形

矢量图形是由数学方程描述的二维图形,通常使用直线、曲线、多边形和文本等基本几何形状来创建。相比于位图图像(如JPEG、PNG等),矢量图形不会失真或模糊,无论放大或缩小都保持清晰度,因为它们是基于数学公式创建的,并且可以被无限放大或缩小而不会失去精度。此外,矢量图形还可以编辑和修改,使得它们在设计、制作标志、海报、传单、名片、网站等方面的应用非常广泛。

使用Base64编码的图片具有以下优点:

  1. 减少HTTP请求:将多个小图片合并为一个Base64编码字符串,可以减少浏览器与服务器之间的HTTP请求次数,提高页面加载速度。

  2. 更好的页面性能:由于Base64编码后的图片是直接嵌入在HTML或CSS中的,而不需要额外的文件下载,因此可以更快地加载页面,提高页面性能。

  3. 简单易用:使用Base64编码的图片无需考虑图片路径等问题,只需要将编码后的字符串嵌入到HTML或CSS代码中即可。

  4. 可减少服务器负载:由于使用Base64编码的图片无需额外的文件下载,减少了服务器的负载。这对于高流量网站来说非常重要。

缺点:

  1. 图片大小增大:由于Base64编码会将图片转换成文本形式,因此会使得图片的大小增加约1/3左右。

  2. 编码和解码需要计算资源:由于编码和解码都需要进行大量的计算,因此可能会影响页面加载速度。

  3. 不适合大型图片:对于较大的图片(尤其是超过几百KB的图片),使用Base64编码会导致HTML或CSS文件变得非常大,影响页面加载速度。

优化大量图片的加载方法,提高用户体验:

  1. 压缩图片:使用图片压缩工具,将图片大小进行压缩,可以减少图片文件的大小,从而加快加载速度。

  2. 使用图片CDN:将图片存储在专门的CDN(内容分发网络)服务器上,可以使得图片加载更快,同时也减轻了原始服务器的负载。

  3. 延迟加载:将页面上非关键图片设置为延迟加载,当用户滚动到页面的对应位置时再加载图片,可以减少初始加载时的负担,提高页面的加载速度和响应性。

  4. 使用矢量图形代替位图:对于一些简单的图标和装饰性元素,可以使用矢量图形代替位图。矢量图形在放大或缩小时不会失真,并且通常比位图更小。

  5. 利用浏览器缓存:将图片缓存在用户的浏览器中,可以减少重复加载同一张图片的次数,提高页面加载速度。

  6. 懒加载:懒加载可以避免在页面中加载不必要的图片,只有用户需要查看某张图片时才会被加载。这种方式可以大幅减少初始页面加载时间,提高用户体验。

  7. 合并多个小图片成一张大图:将多张小图片合并到一张大图中,通过CSS定位显示指定位置的小图片,可以减少请求次数,提高页面加载速度。

优雅降级和渐进增强

优雅降级:在编写项目时,直接针对最高级、最稳定的版本进行开发。然后在后续对低版本进行兼容。 渐进增强:在编写项目时,针对自己想个兼容的最低版本进行开发。然后在后续对高版本的新特性开发,或者更好的体验

新项目css架构设计入手方向

  1. 公共变量(主题色/主要空隙/主要字号字体等)
  2. 编译器(scss/less/postcss/stylus)
  3. 自适应方案(栅格/rem/vw/pt)
  4. 目录约定(mixin/common/theme/module/response)
  5. 私有化方案(scoped/css module/css in js)

Tailwindcss断点对应设备

Breakpoint prefixMinimum widthCSS代表设备
不写--手机
sm640px@media (min-width: 640px) { ... }大屏手机
md768px@media (min-width: 768px) { ... }768-1024代表 Ipad(Ipad Mini = 768)
lg1024px@media (min-width: 1024px) { ... }iPad Pro
xl1280px@media (min-width: 1280px) { ... }小型笔记本
2xl1536px@media (min-width: 1536px) { ... }电脑显示器
+ + + + \ No newline at end of file diff --git "a/Interview/CSS/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" "b/Interview/CSS/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" new file mode 100644 index 00000000..c3643279 --- /dev/null +++ "b/Interview/CSS/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" @@ -0,0 +1,171 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

实现一个元素的宽高比

css
.wrapper {
+    width: 100%;
+    height: 0;
+    padding-top: 56.25%; /* 16:9 宽高比 */
+    position: relative;
+}
+
+.content {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+}
.wrapper {
+    width: 100%;
+    height: 0;
+    padding-top: 56.25%; /* 16:9 宽高比 */
+    position: relative;
+}
+
+.content {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+}

维持正方形: 宽度发生改变时,利用伪元素撑开高度,从而保持正方形。

css
.square::after {
+  content: "";
+  display: block;
+  padding-bottom: 100%;
+}
.square::after {
+  content: "";
+  display: block;
+  padding-bottom: 100%;
+}

Sass 中@mixin 与@extend的区别

主要区别在于代码生成的方式

@mixin会直接将@mixin中的样式复制到@include处,而@extend则会生成一个新的选择器,并继承被@extend的选择器的样式。 因此,@mixin适用于将一组样式应用于多个选择器,而@extend适用于继承现有样式并生成新的选择器。

scss

+/* @extend:在现有样式加上加上新类名 */
+.button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @extend .button-style;
+}
+
+.button-secondary {
+  @extend .button-style;
+}
+
+/* @mixin:把样式复制到指定类名 */
+@mixin button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @include button-style;
+}
+
+.button-secondary {
+  @include button-style;
+}

+/* @extend:在现有样式加上加上新类名 */
+.button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @extend .button-style;
+}
+
+.button-secondary {
+  @extend .button-style;
+}
+
+/* @mixin:把样式复制到指定类名 */
+@mixin button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @include button-style;
+}
+
+.button-secondary {
+  @include button-style;
+}

转化结果:

css
@charset "UTF-8";
+/* @extend:在现有样式加上加上新类名 */
+.button-style, .button-secondary, .button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+/* @mixin:把样式复制到指定类名 */
+.button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-secondary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
@charset "UTF-8";
+/* @extend:在现有样式加上加上新类名 */
+.button-style, .button-secondary, .button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+/* @mixin:把样式复制到指定类名 */
+.button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-secondary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+ + + + \ No newline at end of file diff --git "a/Interview/CSS/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" "b/Interview/CSS/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" new file mode 100644 index 00000000..bc54f78a --- /dev/null +++ "b/Interview/CSS/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" @@ -0,0 +1,31 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Interview/JavaScript/Promise\347\233\270\345\205\263.html" "b/Interview/JavaScript/Promise\347\233\270\345\205\263.html" new file mode 100644 index 00000000..1d6a2fff --- /dev/null +++ "b/Interview/JavaScript/Promise\347\233\270\345\205\263.html" @@ -0,0 +1,305 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

前端如何做到并发请求

  1. 使用AJAX及其各种高级封装的异步技术,如jQuery的$.ajax()、axios等;
  2. 使用Promise(ES6)异步编程,如使用axios.all()或者Promise.all()多个请求并发发出;
  3. 使用Web Workers技术,将任务并发分发到多个Web Worker中执行;
  4. 使用WebSocket技术,可单个持久链接上进行多次请求;
  5. 使用Stream API技术,浏览器可以同时消费多个数据流,实现多个请求的并发;
  6. 使用定时器setInterval()及setTimeout(),可定时发出多个需要并发请求;

方法一:封装队列

js
 class taskQueue {
+    constructor() {
+      this.queue = [];
+      this.result = [];
+      this.error = [];
+      this.max = 3;
+      setTimeout(() => {
+        this.run();
+      }, 0);
+    }
+    addTask(task) {
+      this.queue.push(task);
+    }
+    async run() {
+      const length = this.queue.length;
+      if (length === 0) return;
+      const min = Math.min(length, this.max);
+      for (let i = 0; i < min; i++) {
+        this.max--; //开始占用任务空间
+        const task = this.queue.shift();
+        try {
+          const res = await task();
+          console.log("[ res ]-131", res);
+          this.result.push(res);
+        } catch (err) {
+          this.error.push(err);
+        } finally {
+          this.max++; //释放占用空间
+          this.run();
+        }
+      }
+    }
+  }
+
+  //测试
+  function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const task = new taskQueue();
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  times.forEach((item) => {
+    task.addTask(createTask(item));
+  });
 class taskQueue {
+    constructor() {
+      this.queue = [];
+      this.result = [];
+      this.error = [];
+      this.max = 3;
+      setTimeout(() => {
+        this.run();
+      }, 0);
+    }
+    addTask(task) {
+      this.queue.push(task);
+    }
+    async run() {
+      const length = this.queue.length;
+      if (length === 0) return;
+      const min = Math.min(length, this.max);
+      for (let i = 0; i < min; i++) {
+        this.max--; //开始占用任务空间
+        const task = this.queue.shift();
+        try {
+          const res = await task();
+          console.log("[ res ]-131", res);
+          this.result.push(res);
+        } catch (err) {
+          this.error.push(err);
+        } finally {
+          this.max++; //释放占用空间
+          this.run();
+        }
+      }
+    }
+  }
+
+  //测试
+  function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const task = new taskQueue();
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  times.forEach((item) => {
+    task.addTask(createTask(item));
+  });

方法二:函数封装

js
// 并发请求函数
+const concurrencyRequest = (tasks, maxNum) => {
+  return new Promise((resolve) => {
+    if (tasks.length === 0) {
+      resolve([]);
+      return;
+    }
+    const results = [];
+    let index = 0; // 下一个请求的下标
+    let count = 0; // 当前请求完成的数量
+
+    // 发送请求
+    async function request() {
+      if (index === tasks.length) return;
+      const i = index; // 保存序号,使result和tasks相对应
+      index++;
+      try {
+        const resp = await tasks[i]();
+        console.log("[ resp ]-29", resp);
+        results[i] = resp;
+      } catch (err) {
+        results[i] = err;
+      } finally {
+        count++;
+        // 判断是否所有的请求都已完成
+        if (count === tasks.length) {
+          console.log("完成了");
+          resolve(results);
+        }
+        request();
+      }
+    }
+    const times = Math.min(maxNum, tasks.length);
+    for (let i = 0; i < times; i++) {
+      request();
+    }
+  });
+};
+
+//测试代码
+function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  const tasks = times.map((item) => createTask(item));
+  console.log("[ tasks ]-141", tasks);
+  concurrencyRequest(tasks, 3).then((res) => {
+    console.log("[ res ]-143", res);
+  });
// 并发请求函数
+const concurrencyRequest = (tasks, maxNum) => {
+  return new Promise((resolve) => {
+    if (tasks.length === 0) {
+      resolve([]);
+      return;
+    }
+    const results = [];
+    let index = 0; // 下一个请求的下标
+    let count = 0; // 当前请求完成的数量
+
+    // 发送请求
+    async function request() {
+      if (index === tasks.length) return;
+      const i = index; // 保存序号,使result和tasks相对应
+      index++;
+      try {
+        const resp = await tasks[i]();
+        console.log("[ resp ]-29", resp);
+        results[i] = resp;
+      } catch (err) {
+        results[i] = err;
+      } finally {
+        count++;
+        // 判断是否所有的请求都已完成
+        if (count === tasks.length) {
+          console.log("完成了");
+          resolve(results);
+        }
+        request();
+      }
+    }
+    const times = Math.min(maxNum, tasks.length);
+    for (let i = 0; i < times; i++) {
+      request();
+    }
+  });
+};
+
+//测试代码
+function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  const tasks = times.map((item) => createTask(item));
+  console.log("[ tasks ]-141", tasks);
+  concurrencyRequest(tasks, 3).then((res) => {
+    console.log("[ res ]-143", res);
+  });

Web Worker

可以创建一个独立线程, 因为不会阻塞主线程运行,可以将比较耗费资源操作放在里面执行,比如耗时计算,可以通过 postMessage 进行线程间通信

js
// 主线程
+var worker = new Worker('worker.js')
+worker.postMessage([10, 24])
+worker.onmessage = function(e) {
+    console.log(e.data)
+}
+
+// Worker 线程
+onmessage = function (e) {
+    if (e.data.length > 1) {
+        postMessage(e.data[1] - e.data[0])
+    }
+}
+
+// 主线程
+worker.terminate()
// 主线程
+var worker = new Worker('worker.js')
+worker.postMessage([10, 24])
+worker.onmessage = function(e) {
+    console.log(e.data)
+}
+
+// Worker 线程
+onmessage = function (e) {
+    if (e.data.length > 1) {
+        postMessage(e.data[1] - e.data[0])
+    }
+}
+
+// 主线程
+worker.terminate()

在 Worker 线程中,self 和 this 都代表子线程的全局对象。对于监听 message 事件,以下的四种写法:

js
// 写法 1
+self.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 2
+this.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 3
+addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 4
+onmessage = function (e) {
+    // ...
+}
// 写法 1
+self.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 2
+this.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 3
+addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 4
+onmessage = function (e) {
+    // ...
+}

Service Worker

服务器与浏览器之间的中间人,如果网站中注册了Service Worker那么它可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器,我们在Service Worker 中可以做拦截客户端的请求、向客户端发送消息、向服务器发起请求等先关操作,其中最重要且广泛的的作用就是离线资源缓存。

特性

  1. 基于web worker(JavaScript主线程的独立线程,如果执行消耗大量资源的操作也不会堵塞主线程)
  2. 在web worker的基础上增加了离线缓存的能力
  3. 本质上充当Web应用程序(服务器)与浏览器之间的代理服务器
  4. 创建有效的离线体验(将一些不常更新的内容缓存在浏览器,提高访问体验)
  5. 由事件驱动的,具有生命周期
  6. 可以访问cache和indexDB
  7. 支持消息推送
  8. 并且可以让开发者自己控制管理缓存的内容以及版本
  9. 可以通过 postMessage 接口把数据传递给其他JS 文件
  10. 更多无限可能

WARNING

不能访问 DOM、不能同步操作

+ + + + \ No newline at end of file diff --git "a/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.html" "b/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.html" new file mode 100644 index 00000000..06f76e80 --- /dev/null +++ "b/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.html" @@ -0,0 +1,121 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

new 对象的执行过程

  1. 创建一个新对象:new操作符会创建一个新对象,该对象会继承自构造函数的原型对象。

  2. 设置对象的原型:新对象的__proto__属性会被设置为构造函数的原型对象prototype

  3. 执行构造函数:构造函数会被执行,this 指向新创建的对象。在构造函数内部,可以通过this关键字来添加属性和方法到新对象中。

  4. 对构造函数有返回值的处理判断:

    1. 如果构造函数没有显式地返回对象,返回新创建的对象;(基本类型忽略)
    2. 如果构造函数返回了一个对象,则返回该对象。(引用类型返回)
js
function Person(name, age) {
+  this.name = name;
+  this.age = age;
+}
+
+var person = new Person('Alice', 18);
+console.log(person); // { name: 'Alice', age: 18 }
+//new Person('Alice', 18)会创建一个新的对象,并执行Person函数,将this关键字指向新对象。最后返回新对象,赋值给变量person。
function Person(name, age) {
+  this.name = name;
+  this.age = age;
+}
+
+var person = new Person('Alice', 18);
+console.log(person); // { name: 'Alice', age: 18 }
+//new Person('Alice', 18)会创建一个新的对象,并执行Person函数,将this关键字指向新对象。最后返回新对象,赋值给变量person。

原型和原型链

作用:解决构造函数浪费内存问题,实现对象属性和方法的共享。

js
function Star(){
+
+}
+let star1 = new Star
+ star1.__proto__ === star1.constructor.prototype 
+ Star === Start.prototype.constructor
+ Object.prototype.__proto__ //null
+ Object instanceof Function   //Object顶级对象是 顶级构造器 Fcuntion 的实例
function Star(){
+
+}
+let star1 = new Star
+ star1.__proto__ === star1.constructor.prototype 
+ Star === Start.prototype.constructor
+ Object.prototype.__proto__ //null
+ Object instanceof Function   //Object顶级对象是 顶级构造器 Fcuntion 的实例

2023-03-03-14-31-082023-03-03-14-55-442023-03-03-16-50-56

函数的隐式原型对象

js
function test(){}
+test.__proto__ == Function.prototype   //ture
function test(){}
+test.__proto__ == Function.prototype   //ture

本身 ---> 构造函数.prototype(本身.__proto__) ---> 构造函数原型对象的原型.prototype.__proto__...--->Object.prototype ---> null

JS继承有哪些方式

方式一:ES6

js
class Parent{
+	constructor(){
+		this.age = 18;
+	}
+}
+
+class Child extends Parent{
+	constructor(){
+		super();
+		this.name = '张三';
+	}
+}
+let o1 = new Child();
+console.log( o1,o1.name,o1.age );
class Parent{
+	constructor(){
+		this.age = 18;
+	}
+}
+
+class Child extends Parent{
+	constructor(){
+		super();
+		this.name = '张三';
+	}
+}
+let o1 = new Child();
+console.log( o1,o1.name,o1.age );

方式二:原型链继承

js
function Parent(){
+	this.age = 20;
+}
+function Child(){
+	this.name = '张三'
+}
+//子构造函数原型对象指向父构造函数实例
+Child.prototype = new Parent();
+let o2 = new Child();
+console.log( o2,o2.name,o2.age );
function Parent(){
+	this.age = 20;
+}
+function Child(){
+	this.name = '张三'
+}
+//子构造函数原型对象指向父构造函数实例
+Child.prototype = new Parent();
+let o2 = new Child();
+console.log( o2,o2.name,o2.age );

方式三:借用构造函数继承

function Parent(){
+	this.age = 22;
+}
+function Child(){
+	this.name = '张三'
+	Parent.call(this);
+}
+let o3 = new Child();
+console.log( o3,o3.name,o3.age );
function Parent(){
+	this.age = 22;
+}
+function Child(){
+	this.name = '张三'
+	Parent.call(this);
+}
+let o3 = new Child();
+console.log( o3,o3.name,o3.age );
+ + + + \ No newline at end of file diff --git "a/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" "b/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" new file mode 100644 index 00000000..3a75fa2f --- /dev/null +++ "b/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.html" @@ -0,0 +1,407 @@ + + + + + + 常见基础面试题 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

常见基础面试题

数据类型

原始类型:number,string,boolean,null,undefined,bigint,symbol

引用类型:Object

  • 标准普通对象:Object
  • 标准准特殊对象:Array,Date,Math,Error,RegExp
  • 非标准特殊对象(包装类型):Number,String,Boolean
  • 可执行对象:Function

Symbol应用

  1. 对象唯一值属性
  2. 唯一标识统一管理(pinia 中的 storeId)
  3. iterator底层实现机制

类型检测方式

  1. typeof:所有数据类型,在计算机底层都是按照‘64 位二进制’进行存储的, typeof是按照二进制值进行检测类型的
    详细转换机制
  2. 若二进制前三位是‘0’,并且实现了 call 方法,则返回 function,没有实现则返回 object
  3. null是 64 个 ‘0’,typeof null ---> 'object'(局限性)
  4. 检测未被声明的变量,返回 undefined :::
js
const isObj = option =>  option !== null && (typeof option === 'object' || typeof option === 'function')
const isObj = option =>  option !== null && (typeof option === 'object' || typeof option === 'function')

数据类型转换

其他类型转为数字类型

规则:

  1. 宇符串转换为数宇:空宇符串变为0,如果出现任何非有效数宇宇符,结果都是NaN

  2. 把布尔转换为数宇true->1 ; false->0

  3. null->0 ; undefined->NaN

  4. Symbol无法转换为数宇,会报错:Uncaught TypeError

  5. BigInt转为数字,会去除“n”(超过安全数宇的,会按照科学计数法处理)

  6. 把对象转换为数字

  • 先调用对線的 Symbol.toPrimitive 这个方法,如果不存在这个方法
  • 再调用对泉的 valueof 获取原始值,如果获取的值不是原始值,比如数组
  • 再调用对線的 toString 把其变为字符串
  • 最后再把宇符串基于Number方法转换为数字
js
parseInt(val,radix) parseFloat(val)
+parseInt(null)  parseInt(undefined) -> NaN
+/*  规则:val 必须是字符串,不是则自动转为字符串;
+      然后再 从左往右 找符合 radix(进制)有效数字,一个没找到则返回 NaN,
+      遇到一个非有效数字字符,则停止查找,并 parseInt(之前符合的字符串)  parseInt('12px') -> 12
+*/
parseInt(val,radix) parseFloat(val)
+parseInt(null)  parseInt(undefined) -> NaN
+/*  规则:val 必须是字符串,不是则自动转为字符串;
+      然后再 从左往右 找符合 radix(进制)有效数字,一个没找到则返回 NaN,
+      遇到一个非有效数字字符,则停止查找,并 parseInt(之前符合的字符串)  parseInt('12px') -> 12
+*/

2023-03-04-22-31-38

其他类型转为字符串

隐式转换:String(val)

js
let a = '10'
+let n = a++ // 10(数字)  ++a / a++ 一定是数字运算
+//+出现在左边,转换为数字    +'10'->10
let a = '10'
+let n = a++ // 10(数字)  ++a / a++ 一定是数字运算
+//+出现在左边,转换为数字    +'10'->10

2023-03-04-22-57-17

其他类型转为布尔类型

除了falsy值: 0、-0、NaN、null、undefined、空串,其余都是 true

相等与全等区别

相等(==):两边数据类型不同,会先进行类型转换,再进行比较

  1. 对象与字符串:对象转字符串 Symbol.toPrimitive -> valueOf -> toString,再比较
  2. null == undefined --> true ;null/undefined 与其他任何值都不相等
  3. 对象与对象,比较的是内存地址是否相同
  4. NaN 与其他,NaN 不与任何值相等,NaN == NaN --> false
  5. 除了以上情况,只要两边类型不一致,剩下的都是转为数字,再进行比较

全等(===):两个操作数类型相同,值也需相同才返回 true

可用==的情况:使用时相当于 obj.a === null || obj.a === undefined

  1. 判断对象的属性是否存在 obj.a == null
  2. 判断函数的参数是否存在 arg == null
面试题
js
//题1:
+[] == false   -> 0 == 0   -> false
+![] == false  -> false == false   -> true
+
+//题2:
+var a = ?;
+if(a == 1 && a == 2 && a == 3){
+  console.log('OK')
+}
+//解法一:利用==会进行类型转换,对象转为数字会经历:
+//Symbol.toPrimitive -> valueOf -> toString
+var a = {
+  i: 0,
+  [Symbol.toPrimitive](){
+    return ++this.i
+  }
+}
+//解法二:重写 toString
+var a = [1, 2, 3]
+a.toString = a.shift
+
+//解法三: 数据劫持
+var i = 0
+Object.defineProperty(window, 'a', {
+  get(){
+    return ++i
+  }
+})
//题1:
+[] == false   -> 0 == 0   -> false
+![] == false  -> false == false   -> true
+
+//题2:
+var a = ?;
+if(a == 1 && a == 2 && a == 3){
+  console.log('OK')
+}
+//解法一:利用==会进行类型转换,对象转为数字会经历:
+//Symbol.toPrimitive -> valueOf -> toString
+var a = {
+  i: 0,
+  [Symbol.toPrimitive](){
+    return ++this.i
+  }
+}
+//解法二:重写 toString
+var a = [1, 2, 3]
+a.toString = a.shift
+
+//解法三: 数据劫持
+var i = 0
+Object.defineProperty(window, 'a', {
+  get(){
+    return ++i
+  }
+})

怎么解决精度问题

根本原因:所有数据类型在计算机底层都是以64位二进制存储的,可能出现无限循环,超过 64 位部分被丢弃

  1. 将数字转为整数【扩大系数法】
  2. 第三方库:Math.js, decimal.js, big.js

var/let/const 区别

varletconst
变量提升支持不支持不支持
块级作用域没有
暂存性死区没有存在存在
能否修改变量的值不能修改
变量的值不能修改允许不允许不允许

函数声明会覆盖其他的同名的变量声明。如果有多个函数声明,则是由最后的一个函数声明覆盖之前所有的声明。

const

  1. 声明必须初始化

  2. 只读常量,变量的值不能修改

    • 简单类型 :值就保存在变量指向的那个内存地址,等同于常量。

    • 引用类型:变量指向的内存地址,保存的只是一个指向实际数据的指针;

      const 只能保证指针固定,不能控制指向的数据结构。

暂存性死区

暂存性死区

暂存性死区:使用 let / const 定义该变量之前的区域,

不能在声明前访问,作用域内被声明,不受外部影响

基于 let/const 变量声明,在词法解析阶段就已经明确了未来上下文中必定会有相关变量声明;

如果在声明前使用,则报错 Uncaught ReferenceError

this指向

  1. 全局作用域中或者普通函数中指向全局对象window
  2. 立即执行函数必定指向window
  3. 构造函数中指向对象实例
  4. 事件绑定指向事件源对象
  5. 方法中谁调用就指向谁
  6. 定时器回调为普通函数指向window,箭头函数指向声明时所在外部作用域
  7. forEach等回调函数默认指向window,指定第二个参数存在则指向第二个参数
  8. 严格模式指向window的变为undefined

防抖与节流

防抖:频繁触发某个事件时,在设定的时间内再次触发,会重新清除上一次定时器,重新开启定时器开始计时。

节流:频繁触发某个事件时,保证设定的时间内只会执行一次,只有等执行完才会打开节流阀执行下一个事件。

防抖

js
//实现原理:每次触发事件时,取消之前的定时器,重新计时
+function debounce(func,delay = 500){
+
+  let timer = null
+  return function(...args){
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      func.apply(this,args)
+    },delay)
+  }
+}
//实现原理:每次触发事件时,取消之前的定时器,重新计时
+function debounce(func,delay = 500){
+
+  let timer = null
+  return function(...args){
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      func.apply(this,args)
+    },delay)
+  }
+}
防抖拓展写法
js
function debounce(func,delay = 500immediate=false){
+  //参数判断处理
+	if(typeof func !== 'function') throw new TypeError('func is not a funciton')
+  //debounce(func,true)
+  if(typeof delay === 'boolean'){
+     immediate = delay
+     delay = undefined
+  }
+  isNaN(delay = +delay) ? 500 : delay	//若不是数字则默认 500
+	if(typeof immediate !== 'boolean') immediate = false
+  
+  let timer = null
+  return function(...args){
+    //第一次自执行完,timer 已经有值,
+    let now = !timer && immediate
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      //结束边界触发
+      if(!immediate) func.apply(this,args)
+      //清除最后一个定时器
+      timer = clearTimeout(timer)
+    },delay)
+    //若为立即执行,则第一次,开启边界触发
+    if(now) func.apply(this,args)
+  }
+}
function debounce(func,delay = 500immediate=false){
+  //参数判断处理
+	if(typeof func !== 'function') throw new TypeError('func is not a funciton')
+  //debounce(func,true)
+  if(typeof delay === 'boolean'){
+     immediate = delay
+     delay = undefined
+  }
+  isNaN(delay = +delay) ? 500 : delay	//若不是数字则默认 500
+	if(typeof immediate !== 'boolean') immediate = false
+  
+  let timer = null
+  return function(...args){
+    //第一次自执行完,timer 已经有值,
+    let now = !timer && immediate
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      //结束边界触发
+      if(!immediate) func.apply(this,args)
+      //清除最后一个定时器
+      timer = clearTimeout(timer)
+    },delay)
+    //若为立即执行,则第一次,开启边界触发
+    if(now) func.apply(this,args)
+  }
+}

节流

js
//实现原理:每次触发事件时,判断当前是否存在等待执行的延时函数
+//方法一:定时器存在则什么都不做
+function throttle(func,delay){
+  let timer = null
+  return function(...args){
+    if(timer) return 
+    timer = setTimeout(()=>{
+      func.apply(this,...args)
+      timer = null
+    }, delay)
+  }
+}
+//方法二:
+function throttle(func,delay){
+  let flag = true //节流阀:开启状态
+  return function(...args){
+    if(!flag) return 
+    flag = false //已经在处理:关闭
+    setTimeout(() =>{
+      func.apply(this,args)
+      flag = true //处理完:重新打开
+    },delay)
+  }
+  }
+//实现三:当前时间-上次执行时间 > 设定时间,才执行
+funtion throttle(func,delay){
+  let start = 0
+  return function(...args){
+    let now = Data.now()
+    if(now - start > delay){
+       func.apply(this,args)
+   		 start = now
+    }
+  }
+}
//实现原理:每次触发事件时,判断当前是否存在等待执行的延时函数
+//方法一:定时器存在则什么都不做
+function throttle(func,delay){
+  let timer = null
+  return function(...args){
+    if(timer) return 
+    timer = setTimeout(()=>{
+      func.apply(this,...args)
+      timer = null
+    }, delay)
+  }
+}
+//方法二:
+function throttle(func,delay){
+  let flag = true //节流阀:开启状态
+  return function(...args){
+    if(!flag) return 
+    flag = false //已经在处理:关闭
+    setTimeout(() =>{
+      func.apply(this,args)
+      flag = true //处理完:重新打开
+    },delay)
+  }
+  }
+//实现三:当前时间-上次执行时间 > 设定时间,才执行
+funtion throttle(func,delay){
+  let start = 0
+  return function(...args){
+    let now = Data.now()
+    if(now - start > delay){
+       func.apply(this,args)
+   		 start = now
+    }
+  }
+}

应用

​ 防抖:输入框搜索、编辑框实时保存,(手机息屏策略,王者荣耀回城操作)

​ 节流:滚动到底部加载更多、图标跟随鼠标(地铁发车时间,王者荣耀技能冷却)

前端本地存储方式

区别

存储大小存储时间同源策略在同一浏览器的相同域名、不同端口号下
localStorage5M键值对以字符串形式存储,数据长期保留,不主动删除一直存在受限制不可以共享
sessionStorage5M会话结束自动清除(浏览器窗口关闭时)协议隔离跳转的页面可以共享
cookie4kb设置到期时间,过期清除受限制可以共享

用法

localStorage

js
localStorage.setItem('key', 'value');   //添加数据
+let val = localStorage.getItem('key');  //读取数据
+localStorage.removeItem('key');         //移除单个
+localStorage.clear();                   //移除所有
localStorage.setItem('key', 'value');   //添加数据
+let val = localStorage.getItem('key');  //读取数据
+localStorage.removeItem('key');         //移除单个
+localStorage.clear();                   //移除所有

sessionStorage

js
sessionStorage.setItem('key', 'value');  // 保存数据到 sessionStorage
+let data = sessionStorage.getItem('key');//获取数据
+sessionStorage.removeItem('key');        //删除
+sessionStorage.clear();                  //删除所有
sessionStorage.setItem('key', 'value');  // 保存数据到 sessionStorage
+let data = sessionStorage.getItem('key');//获取数据
+sessionStorage.removeItem('key');        //删除
+sessionStorage.clear();                  //删除所有

cookie

js
let cookies = document.cookie           //同源下获取所有cookie
+document.cookie = 'key=value'           //添加
+document.cookie = "key=; expires=xxx"; 	//设定到期时间自动清除
let cookies = document.cookie           //同源下获取所有cookie
+document.cookie = 'key=value'           //添加
+document.cookie = "key=; expires=xxx"; 	//设定到期时间自动清除

IndexedDB

Generator

一是,function关键字与函数名之间有一个星号;

二是,函数体内部使用yield表达式,定义不同的内部状态。

js
function* helloWorldGenerator() {
+  let a = yield 'hello';
+  console.log(a) //123
+  let b = yield 'world';
+  console.log(b) //undefined
+  return 'ending';
+}
+
+var hw = helloWorldGenerator();
+hw.next()
+hw.next(123) //a = 123
function* helloWorldGenerator() {
+  let a = yield 'hello';
+  console.log(a) //123
+  let b = yield 'world';
+  console.log(b) //undefined
+  return 'ending';
+}
+
+var hw = helloWorldGenerator();
+hw.next()
+hw.next(123) //a = 123

nex()传参会赋值给上一次yield的的返回值

异步流程同步化

js
function* test(){
+  let res1 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第一秒执行')
+    },1000)
+  })
+  console.log(res1) //第一秒执行
+  
+   let res2 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第二秒执行')
+    },1000)
+  })
+}
+
+function generatorRunner(fn){
+	let generator = fn()
+  let step = generator.next()
+  //定义递归函数
+  function loop(stepArg,generator){
+    //获取本次 yield 右侧的结果
+    let value = stepArg.value
+    if(value instanceof Promise){
+      //如果是 Promise 对象就在 then 函数的回调中获取本次程序结果
+      //并且等待回调执行的时候进入下一次递归
+      value.then((function(promiseValue){
+        if(!stepArg.done){
+          loop(generator.next(promiseValue),generator)
+        }
+      }
+    }else{
+          //判断程序没有执行完就将本次结果传入下一步进入下一次递归
+  		if(!stepArg.done) loop(generator.next(stepArg.value),generator)
+ 	}
+  }
+  loop(step,generator)
+}
function* test(){
+  let res1 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第一秒执行')
+    },1000)
+  })
+  console.log(res1) //第一秒执行
+  
+   let res2 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第二秒执行')
+    },1000)
+  })
+}
+
+function generatorRunner(fn){
+	let generator = fn()
+  let step = generator.next()
+  //定义递归函数
+  function loop(stepArg,generator){
+    //获取本次 yield 右侧的结果
+    let value = stepArg.value
+    if(value instanceof Promise){
+      //如果是 Promise 对象就在 then 函数的回调中获取本次程序结果
+      //并且等待回调执行的时候进入下一次递归
+      value.then((function(promiseValue){
+        if(!stepArg.done){
+          loop(generator.next(promiseValue),generator)
+        }
+      }
+    }else{
+          //判断程序没有执行完就将本次结果传入下一步进入下一次递归
+  		if(!stepArg.done) loop(generator.next(stepArg.value),generator)
+ 	}
+  }
+  loop(step,generator)
+}

requestAnimationFrame

60HZ/1000ms = 16.67ms(显示屏每毫秒刷新频率)

起因:setTimeout/setInterval是异步 API,设置的时间间隔没办法保证。

解决:为了设置更精确动画时间间隔、达到平滑动画效果。用法类似 setTimeout API, 本质采用的是系统时间间隔,而不是 JS 执行时间间隔。

希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

用法2023-03-02-15-53-32

浅拷贝和深拷贝

解释

浅拷贝:只拷贝一层,属性为对象时只复制值,不复制对象本身,指向同一对象 深拷贝:完全拷贝一份新的,新对象更改不会影响到旧对象

浅拷贝

js
let newObj = Object.assign({},obj) //只拷贝对象自身的可枚举的属性
+let newObj = [...obj]
+
+//数组
+Array.prototype.slice()
+Array.prototype.concat()
+
+let arr = [
+  {
+    name:'zhan',
+    age:23
+  },
+  123,
+  456
+]
+let newArr1 = arr.slice()
+let newArr2 = arr.concat()
+//改变内部的引用类型两者都会有影响
let newObj = Object.assign({},obj) //只拷贝对象自身的可枚举的属性
+let newObj = [...obj]
+
+//数组
+Array.prototype.slice()
+Array.prototype.concat()
+
+let arr = [
+  {
+    name:'zhan',
+    age:23
+  },
+  123,
+  456
+]
+let newArr1 = arr.slice()
+let newArr2 = arr.concat()
+//改变内部的引用类型两者都会有影响
js
//方式一:
+//会忽略undefined,function,RegExp,Date
+let newObj = JSON.parse(JSON.stringify(obj))
+
+//方式二:
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}
//方式一:
+//会忽略undefined,function,RegExp,Date
+let newObj = JSON.parse(JSON.stringify(obj))
+
+//方式二:
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}

事件捕获和冒泡机制

事件传播过程:事件捕获 ---> 目标阶段---> 事件冒泡

事件捕获:从根元素(html)向内传播,直到目标元素,途中会触发绑定事件捕获元素的回调。element.addEventListener(event, function, true)

事件冒泡:从目标元素向外传播,直到根元素,途中会触发绑定事件冒泡元素的回调。onclickaddEventListener默认绑定冒泡阶段。

阻止冒泡:event.stopPropagation()

阻止默认行为:event.preventDefault(),例如:a标签跳转,表单按钮数据提交至服务器。

阻止同一节点其他后绑定事件执行:event.stopImmediatePropagation()

Promise链式调用

是指在一个Promise对象上多次调用then方法,每个then方法都可以接收上一个Promise对象的返回值,

并返回一个新的Promise对象,从而形成一个Promise链 ,从而实现多个异步操作的顺序执行和数据传递。

如果then方法中抛出了异常,那么后续的then方法会被跳过,直接执行catch方法。

如果then方法中返回了一个Promise对象,那么后续的then方法会等待该Promise对象的状态发生改变后再执行。

可以避免回调地狱,使得代码更加清晰易读。

+ + + + \ No newline at end of file diff --git "a/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.html" "b/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.html" new file mode 100644 index 00000000..da326f27 --- /dev/null +++ "b/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.html" @@ -0,0 +1,63 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

字符串常用方法

都不会影响原字符串:因为字符串是不可变的!

  1. 增删改:replace,replaceAll

  2. 增:repeat,concat,padStart,padEnd

  3. 删:substr,substring,slice,trim,trimStart,trimEnd

  4. 改:split,toLowerCase,toUpperCase,toLocaleLowerCase,

    toLocaleUpperCase, String.fromCharCode()

  5. 查:valueOf,at,charAt,charCodeAt,indexOf,lastIndexOf,

    search,includes,match,startsWith,endsWith

charCodeAt与fromCharCode

js
'ABC'.charCodeAt(2)  //67 返回指定索引位的 ASCII 码
+String.fromCharCode(65, 66, 67) //'ABC' 返回 ASCII 码对应的字符
'ABC'.charCodeAt(2)  //67 返回指定索引位的 ASCII 码
+String.fromCharCode(65, 66, 67) //'ABC' 返回 ASCII 码对应的字符

slice 与 substring区别

slice 与 substring

slice 结束索引大于等于 0 时且小于起始索引时,返回空;结束索引大于0从前面计数,小于0从后面计数的原则。

substring 中如果结束索大于起始索引,则会自动将其调换后截取,当参数小于0 时按0处理。

js
let y = "www.map.baidu.com";
+console.log(y.slice(4,11)); //map.bai
+console.log(y.slice(11,4)); //''
+console.log(y.slice(3,-4)); //.map.baidu
+console.log(y.slice(3,0)); //''
+console.log(y.slice(4)); //map.baidu.com
+
+let y = "www.map.baidu.com";
+console.log(y.substring(4,11)); //map.bai
+console.log(y.substring(11,4)); //map.bai
+console.log(y.substring(3,-4)); //www
+console.log(y.substring(3,0)); //www
+console.log(y.substring(4)); //map.baidu.com
let y = "www.map.baidu.com";
+console.log(y.slice(4,11)); //map.bai
+console.log(y.slice(11,4)); //''
+console.log(y.slice(3,-4)); //.map.baidu
+console.log(y.slice(3,0)); //''
+console.log(y.slice(4)); //map.baidu.com
+
+let y = "www.map.baidu.com";
+console.log(y.substring(4,11)); //map.bai
+console.log(y.substring(11,4)); //map.bai
+console.log(y.substring(3,-4)); //www
+console.log(y.substring(3,0)); //www
+console.log(y.substring(4)); //map.baidu.com

valueOf 与 toString 的异同

共同点

都是对象的方法,用于将对象转换成可操作的基本类型值。

valueOftoString
返回值原始值或对象本身对象转换成可阅读的字符串
能否接受参数转换基数不可以可以,返回不同进制的字符串形式的数值
Date类型返回现在到1970年1月1日的毫秒数时间的字符串

undefinednull 都没有toString() valueOf() 方法

Object.prototype.toString.toString() 能够很好的判断数据的类型及内置对象

js
Number(10).toString(2)	//'1010'
+Number(10).valueOf(2)		//10
+new Date().toString()		//'Thu Mar 02 2023 11:39:56 GMT+0800 (中国标准时间)'
+new Date().valueOf() 		//1677728421211
Number(10).toString(2)	//'1010'
+Number(10).valueOf(2)		//10
+new Date().toString()		//'Thu Mar 02 2023 11:39:56 GMT+0800 (中国标准时间)'
+new Date().valueOf() 		//1677728421211
+ + + + \ No newline at end of file diff --git "a/Interview/JavaScript/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" "b/Interview/JavaScript/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" new file mode 100644 index 00000000..50af6a89 --- /dev/null +++ "b/Interview/JavaScript/\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.html" @@ -0,0 +1,429 @@ + + + + + + 常见进阶面试题 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

常见进阶面试题

模块化

JS运行的环境全局对象
浏览器window直接支持ES6Module,但是不支持CommonJS
Nodeglobal支持CommonJS,但是不支持ES6Module
WebpackCommon JS&ES6Module都支持,支持相互之间的“混用
Vite基于ES6Module规范,实现模块之间的相互引用

闭包

闭包:作用域的一种特殊应用,内层函数作用域用到了外层函数作用域的变量。由于被内层函数引用,导致外层函数执行完变量不会被释放,就形成了闭包。

闭包案例
js
function func(){
+  const val = 10 
+  return function(){
+    console.log(val)
+  }
+}
+const val = 100
+const fn = func()
+fn()//10
function func(){
+  const val = 10 
+  return function(){
+    console.log(val)
+  }
+}
+const val = 100
+const fn = func()
+fn()//10
js
function fn(){
+  const data = {}
+  return {
+    set: function(key,val){
+      data[key] = val
+    }
+    get:function(key){
+      return data[key]
+    }
+  }
+}
+const handle = fn()
+handle.set('name','zhangsan')
+handle.get('name')
function fn(){
+  const data = {}
+  return {
+    set: function(key,val){
+      data[key] = val
+    }
+    get:function(key){
+      return data[key]
+    }
+  }
+}
+const handle = fn()
+handle.set('name','zhangsan')
+handle.get('name')
js
const btns = document.querySelectorAll('.btn') //5个按钮
+for(val i = 0;i < btns.length; i++){	//改用 let 形成闭包
+	btns[i].onclick = function(){
+    console.log(i) //输出结果都是 5
+  } 
+}
+//==>
+for(val i = 0;i < btns.length; i++){
+(function(){
+ btns[i].onclick = function(){
+      console.log(i) //输出结果: 01234
+  }})(i)
+}
const btns = document.querySelectorAll('.btn') //5个按钮
+for(val i = 0;i < btns.length; i++){	//改用 let 形成闭包
+	btns[i].onclick = function(){
+    console.log(i) //输出结果都是 5
+  } 
+}
+//==>
+for(val i = 0;i < btns.length; i++){
+(function(){
+ btns[i].onclick = function(){
+      console.log(i) //输出结果: 01234
+  }})(i)
+}

应用

  1. 函数柯里化
  2. 变量私有化

弊端

过度使用闭包会造成内存占用过多,容易造成内存泄漏,手动清空可解决问题。

函数柯里化

数组求和
js
let arr = [1,2,3,4]
+//方法一:
+let sum = arr.reduce((pre,cur) => pre + cur,0)
+//方法二:
+eval(arr.join('+'))
let arr = [1,2,3,4]
+//方法一:
+let sum = arr.reduce((pre,cur) => pre + cur,0)
+//方法二:
+eval(arr.join('+'))
实现 add(1,2)(3)
js
const add = function(...params){ // params:[1,2]
+  return function(...args){ //args:[3]
+    return params.concat(args).reduce((pre,cur) => cur+pre)
+  }
+}
+//简化
+const add = (...params) => (...args) => params.concat(args).reduce((pre,cur) => pre + cur)
const add = function(...params){ // params:[1,2]
+  return function(...args){ //args:[3]
+    return params.concat(args).reduce((pre,cur) => cur+pre)
+  }
+}
+//简化
+const add = (...params) => (...args) => params.concat(args).reduce((pre,cur) => pre + cur)
实现 add(1)(2)(3)
js
const add = function(a){
+  return function(b){
+    return function(c){
+      return a + b + c
+    }
+  }
+}
+//简化
+const add = a => b => c => a + b + c 
+
+//柯里化:curring 函数
+const curring = function(){
+  let params = []//利用闭包存储实参
+  const add = (...args) =>{
+    params = params.concat(args)
+    return add
+  }
+  //在对象转数字过程中,进行求和处理
+  add[Symbol.toPrimitive] = () => {
+    return params.reduce((pre,cur) => pre + cur)
+  }
+  return add
+}
+const add = curring()
+let sum = add(1)(2)(3)(4)(5)(6)
+alert(sum) //21
+console.log(+sum)//21
const add = function(a){
+  return function(b){
+    return function(c){
+      return a + b + c
+    }
+  }
+}
+//简化
+const add = a => b => c => a + b + c 
+
+//柯里化:curring 函数
+const curring = function(){
+  let params = []//利用闭包存储实参
+  const add = (...args) =>{
+    params = params.concat(args)
+    return add
+  }
+  //在对象转数字过程中,进行求和处理
+  add[Symbol.toPrimitive] = () => {
+    return params.reduce((pre,cur) => pre + cur)
+  }
+  return add
+}
+const add = curring()
+let sum = add(1)(2)(3)(4)(5)(6)
+alert(sum) //21
+console.log(+sum)//21

compose

思想:利用闭包预先存储,供其夏季上下文后期使用,可解决函数嵌套导致的可读性差问题。

js
const add1 = x => x + 1
+const mul3 = x => x * 3
+const div2 = x => x / 2
+//不使用柯里化:div2(mul3(add1(10)))
+
+const compose = function(...funcs){
+  //考虑不传函数,返回operate传的实参
+  let len = funcs.length
+  if(len === 0) return x => x
+  if(len === 1) return funcs[0]
+  return function operate(x){
+    return funcs.reduceRight((x,func) => func(x),x)
+  }
+}
+//不传函数
+const operate = compose()
+operate(10) //10
+//传一个
+const operate = compose(add1)
+operate(10) //11
+// 传多个
+const operate = compose(div2,mul3,add1,add1)
+operate(10) //18
const add1 = x => x + 1
+const mul3 = x => x * 3
+const div2 = x => x / 2
+//不使用柯里化:div2(mul3(add1(10)))
+
+const compose = function(...funcs){
+  //考虑不传函数,返回operate传的实参
+  let len = funcs.length
+  if(len === 0) return x => x
+  if(len === 1) return funcs[0]
+  return function operate(x){
+    return funcs.reduceRight((x,func) => func(x),x)
+  }
+}
+//不传函数
+const operate = compose()
+operate(10) //10
+//传一个
+const operate = compose(add1)
+operate(10) //11
+// 传多个
+const operate = compose(div2,mul3,add1,add1)
+operate(10) //18

闭包惰性思想

js
function getCss(ele, attr){
+  //加载判断样式兼容问题,没有更换刷新浏览器每次都需要做多余的判断
+  if(window.getComputedStyle){
+      return window.getComputedStyle(ele)[attr]
+  }else{
+      return window.getCurrentStyle(ele)[attr]
+  }
+}
+//优化后
+function getCss(ele, attr){
+  //第一次运行,根据兼容情况,重构 getCss
+  if(window.getComputedStyle){
+    getCss = function(ele, attr){
+      return window.getComputedStyle(ele)[attr]
+    }
+  }else{
+    getCss = function(ele, attr){
+      return window.getCurrentStyle(ele)[attr]
+    }
+  }
+  return getCss(ele, attr)
+}
+getCss(body, 'width')
+getCss(body, 'padding')
function getCss(ele, attr){
+  //加载判断样式兼容问题,没有更换刷新浏览器每次都需要做多余的判断
+  if(window.getComputedStyle){
+      return window.getComputedStyle(ele)[attr]
+  }else{
+      return window.getCurrentStyle(ele)[attr]
+  }
+}
+//优化后
+function getCss(ele, attr){
+  //第一次运行,根据兼容情况,重构 getCss
+  if(window.getComputedStyle){
+    getCss = function(ele, attr){
+      return window.getComputedStyle(ele)[attr]
+    }
+  }else{
+    getCss = function(ele, attr){
+      return window.getCurrentStyle(ele)[attr]
+    }
+  }
+  return getCss(ele, attr)
+}
+getCss(body, 'width')
+getCss(body, 'padding')

深度优先和广度优先

js
//数据
+let tree =  {
+    id: '1',
+    title: '节点1',
+    children: [
+      {
+        id: '1-1',
+        title: '节点1-1'
+      },
+      {
+        id: '1-2',
+        title: '节点1-2',
+        children: [{
+          id: '2',
+          title: '节点2',
+          children: [
+            {
+              id: '2-1',
+              title: '节点2-1'
+            }
+          ]
+        }]
+      }
+    ]
+  }
//数据
+let tree =  {
+    id: '1',
+    title: '节点1',
+    children: [
+      {
+        id: '1-1',
+        title: '节点1-1'
+      },
+      {
+        id: '1-2',
+        title: '节点1-2',
+        children: [{
+          id: '2',
+          title: '节点2',
+          children: [
+            {
+              id: '2-1',
+              title: '节点2-1'
+            }
+          ]
+        }]
+      }
+    ]
+  }

深度优先遍历(DFS)

深度优先遍历(DFS)是一种递归或栈的思想来遍历所有节点的算法。在 JavaScript 中,可以使用递归或栈来实现 DFS。具体步骤如下:

  1. 访问根节点
  2. 对根节点的所有子节点,依次执行以下操作:
    • 访问该子节点
    • 对该子节点的所有子节点,依次执行以上两步操作

JavaScript 中 DFS 的时间复杂度为 O(n),其中 n 是节点数。空间复杂度为 O(h),其中 h 是树的高度。

js
//递归方式
+let dfs = (node, nodes = []) => {
+  if (node) {
+    nodes.push(node.id)
+    node.children?.forEach(child =>	dfs(child, nodes) )
+  }
+  return nodes
+}
//递归方式
+let dfs = (node, nodes = []) => {
+  if (node) {
+    nodes.push(node.id)
+    node.children?.forEach(child =>	dfs(child, nodes) )
+  }
+  return nodes
+}
js
//非递归方式
+let dfs = (node) => {
+  let nodes = []
+  let stack = []
+  if(node){
+    stack.push(node)
+    while(stack.length){
+      let item = stack.shift()
+      let children = item.children
+      nodes.push(item.id)
+      children?.forEach(child => stack.push(child) )
+    }
+  }
+  return nodes
+}
//非递归方式
+let dfs = (node) => {
+  let nodes = []
+  let stack = []
+  if(node){
+    stack.push(node)
+    while(stack.length){
+      let item = stack.shift()
+      let children = item.children
+      nodes.push(item.id)
+      children?.forEach(child => stack.push(child) )
+    }
+  }
+  return nodes
+}
js
// 用非递归方式实现二叉树深度优先遍历
+function dfs(node) {
+  let nodes = [];
+  if (node) {
+    nodes.push(node);
+    node.children?.forEach(child => nodes = nodes.concat(dfs(child)))
+  }
+  return nodes;
+}
// 用非递归方式实现二叉树深度优先遍历
+function dfs(node) {
+  let nodes = [];
+  if (node) {
+    nodes.push(node);
+    node.children?.forEach(child => nodes = nodes.concat(dfs(child)))
+  }
+  return nodes;
+}

广度优先遍历(BFS)

广度优先遍历(BFS)是一种逐层扫描节点的算法。在 JavaScript 中,可以使用队列来实现 BFS。具体步骤如下:

  1. 将根节点入队
  2. 当队列非空时,执行以下操作:
    • 将队头节点出队,并访问该节点
    • 将该节点的所有子节点入队

JavaScript 中 BFS 的时间复杂度为 O(n),其中 n 是节点数。空间复杂度为 O(w),其中 w 是树的宽度。

js
function bfs(root) {
+  let nodes = []
+  const queue = [root];
+  while (queue.length > 0) {
+    const node = queue.shift();
+    nodes.push(node.id)
+    node.children?.forEach(child => {
+      queue.push(child);
+    });
+  }
+  return nodes
+}
+
+//简化后
+function bfs(root){
+  let nodes = []
+  let node,queue = [root]
+  while(node = queue.shift()){
+    nodes.push(node.id)
+    node.children && queue.push(...node.children)
+  }
+  return nodes
+}
function bfs(root) {
+  let nodes = []
+  const queue = [root];
+  while (queue.length > 0) {
+    const node = queue.shift();
+    nodes.push(node.id)
+    node.children?.forEach(child => {
+      queue.push(child);
+    });
+  }
+  return nodes
+}
+
+//简化后
+function bfs(root){
+  let nodes = []
+  let node,queue = [root]
+  while(node = queue.shift()){
+    nodes.push(node.id)
+    node.children && queue.push(...node.children)
+  }
+  return nodes
+}
js
function bfs(node) {
+  let nodes = []
+  if (node !== null) {
+    nodes.push(node)
+    let i = 0
+    while (node = nodes[i++]) {
+      node.children && nodes.push(...node.children)
+    }
+  }
+  return nodes
+}
function bfs(node) {
+  let nodes = []
+  if (node !== null) {
+    nodes.push(node)
+    let i = 0
+    while (node = nodes[i++]) {
+      node.children && nodes.push(...node.children)
+    }
+  }
+  return nodes
+}

两者的区别

  • 广度优先遍历需要使用队列逐层扫描节点,而深度优先遍历需要使用递归或栈来遍历节点。
  • 广度优先遍历的空间复杂度比深度优先遍历高,因为广度优先遍历需要使用队列来存储节点,而深度优先遍历只需要使用递归或栈。

广度优先遍历的应用

广度优先遍历可以用于许多问题,例如:

  • 查找最短路径:遍历距离起点最近的节点。
  • 查找连通块:可以找到由相邻节点组成的连通块。
  • 查找图的最小生成树

深度优先遍历的应用

  • 查找连通块:可以找到由相邻节点组成的连通块。
  • 查找拓扑排序:可以找到图的拓扑排序,即节点的一个线性序列,使得对于每个有向边 (u,v),都有 u 在序列中排在 v 的前面。
  • 查找强联通分量:通过深度优先遍历,可以找到图的强联通分量,即任意两点之间都存在一条路径的最大子图。

图文详解深度优先,广度优先遍历

loader和plugin区别

Loader

是用来处理单个模块的转换,将各种类型的文件(如 js、css、sass、less、图片等)转换为 Webpack 可以处理的模块;

执行顺序是从后往前依次执行,每个 Loader 都会对文件进行处理,直到最后一个 Loader 将文件转换为模块。

Plugin

是扩展 Webpack 功能的函数,可以在构建过程中执行一系列的任务,遍历所有的 Plugin,并执行它们的 apply 方法。

例如生成 HTML 文件(HtmlWebpackPlugin)、压缩代码(UglifyJsPlugin)、提取公共代码等。

Plugin 在 Loader 执行完成之后执行,可以访问 Webpack 的内部环境,并对其进行修改和优化。

前端模块化规范

前端模块化规范是为了解决前端代码复杂度、可维护性和可扩展性等问题而产生的。目前常用的前端模块化规范有CommonJS、AMD、CMD和ES6 Module等,它们之间的区别如下:

CommonJS规范:主要用于服务器端的JavaScript编程,Node.js采用了该规范。采用同步加载模块的方式,即在需要使用某个模块时,通过require函数同步加载该模块,然后才能执行后续代码。

ES6 Module:是ECMAScript 6标准中新增的模块化规范。 采用静态加载模块的方式,即在编译时就确定模块之间的依赖关系,然后再执行代码。

与其他模块化规范不同的是,ES6 Module不需要使用特定的函数或语法来定义和导入模块,而是使用import和export关键字来实现。

+ + + + \ No newline at end of file diff --git "a/Interview/JavaScript/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" "b/Interview/JavaScript/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" new file mode 100644 index 00000000..22713eab --- /dev/null +++ "b/Interview/JavaScript/\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.html" @@ -0,0 +1,129 @@ + + + + + + 常见高级面试题 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

常见高级面试题

怎么禁止下载图片(midjourney实现)

方案一:禁止右键

html
<img src="image.png" oncontextmenu="return false;" />
<img src="image.png" oncontextmenu="return false;" />
js
window.onload = function() {
+    document.oncontextmenu = function(event) {
+        event.returnValue = false;
+    };
+}
window.onload = function() {
+    document.oncontextmenu = function(event) {
+        event.returnValue = false;
+    };
+}

方案二:禁止拖拽

html
<img src="image.png" ondragstart="return false;" />
<img src="image.png" ondragstart="return false;" />

方案三:使用遮罩层

html
<div style="position: relative; display: inline-block;">
+    <img src="image.png" alt="">
+    <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;
+                background: url(image.png) no-repeat center center / contain; opacity: 0.7;"></div>
+</div>
<div style="position: relative; display: inline-block;">
+    <img src="image.png" alt="">
+    <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;
+                background: url(image.png) no-repeat center center / contain; opacity: 0.7;"></div>
+</div>

方案四:转换为 canvas

js
export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
+  return new Promise((resolve, reject) => {
+    //新建Image对象,引入当前目录下的图片
+    const img = new Image()
+    img.src = url
+    const c = canvas.getContext('2d')!
+
+    //图片初始化完成后调用
+    img.onload = function () {
+      //将canvas的宽高设置为图像的宽高
+      canvas.width = img.width
+      canvas.height = img.height
+
+      //canvas画图片
+      c.drawImage(img, 0, 0, img.width, img.height)
+      resolve()
+    }
+    img.addEventListener('error', (e) => {
+      reject(e)
+    })
+  })
+}
export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
+  return new Promise((resolve, reject) => {
+    //新建Image对象,引入当前目录下的图片
+    const img = new Image()
+    img.src = url
+    const c = canvas.getContext('2d')!
+
+    //图片初始化完成后调用
+    img.onload = function () {
+      //将canvas的宽高设置为图像的宽高
+      canvas.width = img.width
+      canvas.height = img.height
+
+      //canvas画图片
+      c.drawImage(img, 0, 0, img.width, img.height)
+      resolve()
+    }
+    img.addEventListener('error', (e) => {
+      reject(e)
+    })
+  })
+}
js
const throwFn = () => {
+  throw new Error(
+    "Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
+  )
+}
+
+const $canvasRef = useRef<HTMLCanvasElement>(null)
+ useEffect(() => {
+     ;(async () => {
+         await imageToCanvas(props.url, $canvasRef.current!)
+         $canvasRef.current!.toBlob = throwFn
+         $canvasRef.current!.toDataURL = throwFn
+     })()
+ }, [])
+ return (
+     <canvas
+         ref={$canvasRef}
+         onTouchStart={preventDefaultListener}
+         onContextMenu={preventDefaultListener}
+     />
+ )
const throwFn = () => {
+  throw new Error(
+    "Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
+  )
+}
+
+const $canvasRef = useRef<HTMLCanvasElement>(null)
+ useEffect(() => {
+     ;(async () => {
+         await imageToCanvas(props.url, $canvasRef.current!)
+         $canvasRef.current!.toBlob = throwFn
+         $canvasRef.current!.toDataURL = throwFn
+     })()
+ }, [])
+ return (
+     <canvas
+         ref={$canvasRef}
+         onTouchStart={preventDefaultListener}
+         onContextMenu={preventDefaultListener}
+     />
+ )
+ + + + \ No newline at end of file diff --git "a/Interview/Vue/Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.html" "b/Interview/Vue/Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.html" new file mode 100644 index 00000000..c860e989 --- /dev/null +++ "b/Interview/Vue/Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.html" @@ -0,0 +1,31 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

数组劫持原理

  1. 使用 Object.create(Array.prototype) 备份原型上的方法
  2. 利用 AOP 思想,对 7 个变异方法进行重写,重写函数:先调用原来对应方法,再对新增的每一项进行数据劫持
+ + + + \ No newline at end of file diff --git "a/Interview/Vue/Vue\345\237\272\347\241\200\347\257\207.html" "b/Interview/Vue/Vue\345\237\272\347\241\200\347\257\207.html" new file mode 100644 index 00000000..94acecd1 --- /dev/null +++ "b/Interview/Vue/Vue\345\237\272\347\241\200\347\257\207.html" @@ -0,0 +1,31 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

对MVVM的理解

MVVM 由 MVC 模型演变而来,M(Model)代表数据模型,V(View)代表用户操作的界面,VM(ViewModel)代表业务逻辑层,

充当数据模型与视图界面的桥梁,可以把数据绑定到页面,页面操作触发数据更新,数据修改自动触发视图更新。

Mixins的原理

Vue 的 mixins混入 可以抽离封装Vue 组件选项达到复用的效果。

data、provide:后者的值将对前者的值进行扩展,相同属性名(非对象)则以后者的属性值为准,如果两者的值是对象,但值不相等,则继续进行合并,

生命周期钩子函数:将后者的生命周期钩子函数拼接到前者的生命周期钩子函数,调用时依次执行;

components、filters、directives:对前者的属性进行拷贝扩展,属性相同则后者覆盖前者;

**watch:**与生命周期钩子函数类似,将后者的 watch拼接到前者的 watch后面;

props、methods、inject、computed:定义一个对象 ret,遍历前者的属性或方法,对 ret进行扩展,再遍历后者的属性或方法,后者将覆盖前者的属性或方法;

默认策略:策略中没有定义的策略,后者有则返回后者,否则返回前者;

+ + + + \ No newline at end of file diff --git "a/Interview/Vue/Vue\345\243\260\346\230\216\345\221\250\346\234\237.html" "b/Interview/Vue/Vue\345\243\260\346\230\216\345\221\250\346\234\237.html" new file mode 100644 index 00000000..212f9beb --- /dev/null +++ "b/Interview/Vue/Vue\345\243\260\346\230\216\345\221\250\346\234\237.html" @@ -0,0 +1,89 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Vue声明周期

js
//自带 8 个
+beforeCreate
+created
+beforeMount
+mounted
+beforeUpdate
+updated
+beforeDestory
+destoryed
//自带 8 个
+beforeCreate
+created
+beforeMount
+mounted
+beforeUpdate
+updated
+beforeDestory
+destoryed

嵌套组件组件执行顺序

js
//父组件
+beforeCreate
+created
+beforeMount
+  //子组件
+  beforeCreate
+  created
+  beforeMount
+  mounted
+    //孙子组件
+      beforeCreate
+      created
+      beforeMount
+      mounted
//父组件
+beforeCreate
+created
+beforeMount
+  //子组件
+  beforeCreate
+  created
+  beforeMount
+  mounted
+    //孙子组件
+      beforeCreate
+      created
+      beforeMount
+      mounted

beforeCreate 与 created 区别

created 与 mounted 区别

请求问题:当需要子组件的请求需要比父组件完成时,可以把父组件请求卸载mounted中,子组件写在created中。

keep-alive内置缓存组件

额外增加两个声明周期:activated, deactivated

js
//第一次执行顺序
+  beforeCreate
+  created
+  beforeMount
+  mounted
+  activated
+
+  //第二次:多次进入详情页,在activated钩子中,判断 id 相同则不需要发请求
+  activated
//第一次执行顺序
+  beforeCreate
+  created
+  beforeMount
+  mounted
+  activated
+
+  //第二次:多次进入详情页,在activated钩子中,判断 id 相同则不需要发请求
+  activated

虚拟 DOM(VNode) 和 DOM

  1. VNode是一个纯 JavaScript 对象,用来描述真实 DOM 中的一个节点,属性比真实 dom 精简许多。

虚拟 DOM 的优点包括:

性能优化:由于真实 DOM 操作非常耗费性能,而虚拟 DOM 可以在内存中进行操作,然后再一次性渲染到真实 DOM 上,从而减少了不必要的 DOM 操作,提高了性能。

跨平台:虚拟 DOM 可以轻松地支持多种平台,比如浏览器、移动端、服务器端等。

组件化开发:Vue 的组件是以 VNode 为基础的,通过对 VNode 的操作,可以方便地实现组件的开发。

Vue3.0性能提升

  1. 响应式系统不需要深度遍历就可以对整个对象监听
  2. 在diff算法中增加了静态标记
  3. 源码体积减小,所有 API 都可以按需引入
+ + + + \ No newline at end of file diff --git "a/Interview/Vue/Vue\350\277\233\351\230\266\347\257\207.html" "b/Interview/Vue/Vue\350\277\233\351\230\266\347\257\207.html" new file mode 100644 index 00000000..40e844e5 --- /dev/null +++ "b/Interview/Vue/Vue\350\277\233\351\230\266\347\257\207.html" @@ -0,0 +1,31 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Interview/Vue/npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.html" "b/Interview/Vue/npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.html" new file mode 100644 index 00000000..8649fa0a --- /dev/null +++ "b/Interview/Vue/npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.html" @@ -0,0 +1,31 @@ + + + + + + npm run xxx执行过程 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

npm run xxx执行过程

vue cli 项目

  1. npm run 会先把 node_modules/.bin 加入到 PATH 环境变量

  2. 找到项目根目录 package.json 文件中 scripts 对应的脚本并执行对应命令

  3. 相当于执行 vue-cli-service serve ,并去找到npm i (npm i @vue/cli-service)所生成的软连接 ./bin/vue-cli-service

  4. 接着去执行软连接指向的 node_modules/@vue/cli-service/bin/vue-cli-service.js (package-lock.json记录了映射关系)

    1. vue-cli-service.js主要解析和比对 node 版本,不匹配则报错
    2. 获取和解析命令行参数,启动服务执行命令

vite项目

  1. npm run 会先把 node_modules/.bin 加入到 PATH 环境变量
  2. 找到项目根目录 package.json 文件中 scripts 对应的脚本并执行对应命令
  3. 去找.bin/vite 软链接,进而找到 node_modules/.pnpm/vite@4.1.1/node_modules/vite/bin/vite.js执行
+ + + + \ No newline at end of file diff --git "a/Interview/Vue/\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.html" "b/Interview/Vue/\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.html" new file mode 100644 index 00000000..d108682e --- /dev/null +++ "b/Interview/Vue/\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.html" @@ -0,0 +1,117 @@ + + + + + + 前端项目优化 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

前端项目优化

HTML

CSS

JavaScript

构建优化

移除console

npm install babel-plugin-transform-remove-console --D

js
//babel.config.js
+const proPlugins = [];
+if (process.env.NODE_ENV === 'production') {
+  proPlugins.push('transform-remove-console');
+}
+module.exports = {
+  plugins: [
+      ...proPlugins
+  ]
+};
//babel.config.js
+const proPlugins = [];
+if (process.env.NODE_ENV === 'production') {
+  proPlugins.push('transform-remove-console');
+}
+module.exports = {
+  plugins: [
+      ...proPlugins
+  ]
+};

分包和共享依赖

js
 configureWebpack: {
+    resolve: {
+      alias: {
+        "@": resolve("src"),
+      },
+    },
+    optimization: {
+      runtimeChunk: "single",
+      splitChunks: {
+        chunks: "all",
+        maxInitialRequests: Infinity,
+        minSize: 20000,
+        cacheGroups: {
+          common: {
+            name: "common",
+            chunks: "all",
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2,
+          },
+          vendor: {
+            test: /[\\/]node_modules[\\/]/,
+            chunks: "initial", //从入口文件抽离
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2, //只要使用2次以上就抽离
+            name(module) {
+              const packageName = module.context.match(
+                /[\\/]node_modules[\\/](.*?)([\\/]|$)/
+              )[1];
+              return `npm.${packageName.replace("@", "")}`;
+            },
+          },
+        },
+      },
+    },
+  },
 configureWebpack: {
+    resolve: {
+      alias: {
+        "@": resolve("src"),
+      },
+    },
+    optimization: {
+      runtimeChunk: "single",
+      splitChunks: {
+        chunks: "all",
+        maxInitialRequests: Infinity,
+        minSize: 20000,
+        cacheGroups: {
+          common: {
+            name: "common",
+            chunks: "all",
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2,
+          },
+          vendor: {
+            test: /[\\/]node_modules[\\/]/,
+            chunks: "initial", //从入口文件抽离
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2, //只要使用2次以上就抽离
+            name(module) {
+              const packageName = module.context.match(
+                /[\\/]node_modules[\\/](.*?)([\\/]|$)/
+              )[1];
+              return `npm.${packageName.replace("@", "")}`;
+            },
+          },
+        },
+      },
+    },
+  },
+ + + + \ No newline at end of file diff --git "a/Interview/Vue/\345\270\270\350\247\201Path\345\214\272\345\210\253.html" "b/Interview/Vue/\345\270\270\350\247\201Path\345\214\272\345\210\253.html" new file mode 100644 index 00000000..c92eb42a --- /dev/null +++ "b/Interview/Vue/\345\270\270\350\247\201Path\345\214\272\345\210\253.html" @@ -0,0 +1,65 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

VueRouter的 base

VueRouter的base属性是指应用的基路径,它会影响到所有使用了vue-router的路由路径,包括 routes 配置中的路径和 通过 $router.push() 或 $router.replace() 调用的路径。

在router对象中,base属性可以通过以下方式设置:

javascript
const router = new VueRouter({
+  base: '/my-app/'
+})
const router = new VueRouter({
+  base: '/my-app/'
+})

这个属性值的默认值为 '/'。如果你的应用被部署在一个子目录下,你就需要手动指定base属性的值。

例如,假设你的应用被部署在http://example.com/my-app/这个路径下,那么你就需要设置如下的base属性:

javascript
const router = new VueRouter({
+  base: '/my-app/'
+})
const router = new VueRouter({
+  base: '/my-app/'
+})

这个设置是非常重要的,因为Vue Router 路由器的默认行为是从根路径(localhost:8080/) 开始的,

如果你需要从你的实际路径下查看(例如 localhost:8080/my-project/),就需要设置base属性了。

除了上述的情况之外,一般我们都不会配置base属性,这个属性的作用主要是为了适应应用被部署在服务器上的子目录下的情况。

vue.config.js的 publicPath

在 Vue.js 中, publicPath 是用来指定应用程序部署的基础 URL。它作用于构建过程中的静态文件的路径,

同时也影响 Vue Router 中 router-link 组件的路径。一般来说,我们在开发环境和生产环境使用不同的 publicPath 值,来确保应用在不同环境下都能够正确访问静态文件。

以下是一些常见的 publicPath 配置:

  • "/":将生成的静态文件放在根目录下,这是默认值。
  • "./":将生成的静态文件放在当前目录下。
  • "../":将生成的静态文件放在上级目录下。

在 vue.config.js 中,我们可以通过设置 publicPath 来配置应用的部署路径。例如,我们可以将 publicPath 设置为 "/my-app/",

则构建出的静态文件实际上会被部署到类似于 http://example.com/my-app/ 这样的路径下。代码示例:

javascript
module.exports = {
+  publicPath: process.env.NODE_ENV === 'production'
+    ? '/my-app/'
+    : '/'
+}
module.exports = {
+  publicPath: process.env.NODE_ENV === 'production'
+    ? '/my-app/'
+    : '/'
+}

通常可以在根目录配置环境变量,相对于不同环境打包时的打包命令

json
//package.json
+"scripts": {
+    "serve": "vue-cli-service serve --open --port 9999",
+    "build:server": "vue-cli-service build ",
+    "build:local": "vue-cli-service build --mode buildlocal"
+  },
//package.json
+"scripts": {
+    "serve": "vue-cli-service serve --open --port 9999",
+    "build:server": "vue-cli-service build ",
+    "build:local": "vue-cli-service build --mode buildlocal"
+  },
js
//.env.production   --服务器打包预览环境变量
+OUTPUT_DIR=/opt/nginx/www/html/music
+BASE_URL=/music/
//.env.production   --服务器打包预览环境变量
+OUTPUT_DIR=/opt/nginx/www/html/music
+BASE_URL=/music/
js
//.env.buildlocal   --本地打包预览环境变量
+OUTPUT_DIR=dist
+BASE_URL=/
//.env.buildlocal   --本地打包预览环境变量
+OUTPUT_DIR=dist
+BASE_URL=/
+ + + + \ No newline at end of file diff --git "a/Interview/Vue/\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.html" "b/Interview/Vue/\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.html" new file mode 100644 index 00000000..2bb3fc31 --- /dev/null +++ "b/Interview/Vue/\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.html" @@ -0,0 +1,127 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一键复制

js
//方案一:
+Vue.directive('copy', {
+  bind: function (el) {
+    el.addEventListener('click', function () {
+      var range = document.createRange();
+      range.selectNode(el);
+      window.getSelection().addRange(range);
+      document.execCommand('copy');
+      window.getSelection().removeAllRanges();
+    });
+  }
+});
+
+//方案二:
+import { Notification } from "element-ui";
+export const COPY = {
+  bind(el, { value }) {
+    el.$value = value;
+    el.handler = () => {
+      if (!el.$value) {
+        Notification.success({
+          title: "无复制内容",
+        });
+        return;
+      }
+      const textarea = document.createElement("textarea");
+      textarea.readOnly = "readonly";
+      textarea.style.position = "absolute";
+      textarea.style.left = "-9999px";
+      textarea.value = el.$value;
+      document.body.appendChild(textarea);
+      textarea.select();
+      const result = document.execCommand("Copy");
+      if (result) {
+        Notification.success({
+          title: "复制成功",
+        });
+      }
+      document.body.removeChild(textarea);
+    };
+    el.addEventListener("click", el.handler);
+  },
+  componentUpdated(el, { value }) {
+    el.$value = value;
+  },
+  unbind(el) {
+    el.removeEventListener("click", el.handler);
+  },
+};
//方案一:
+Vue.directive('copy', {
+  bind: function (el) {
+    el.addEventListener('click', function () {
+      var range = document.createRange();
+      range.selectNode(el);
+      window.getSelection().addRange(range);
+      document.execCommand('copy');
+      window.getSelection().removeAllRanges();
+    });
+  }
+});
+
+//方案二:
+import { Notification } from "element-ui";
+export const COPY = {
+  bind(el, { value }) {
+    el.$value = value;
+    el.handler = () => {
+      if (!el.$value) {
+        Notification.success({
+          title: "无复制内容",
+        });
+        return;
+      }
+      const textarea = document.createElement("textarea");
+      textarea.readOnly = "readonly";
+      textarea.style.position = "absolute";
+      textarea.style.left = "-9999px";
+      textarea.value = el.$value;
+      document.body.appendChild(textarea);
+      textarea.select();
+      const result = document.execCommand("Copy");
+      if (result) {
+        Notification.success({
+          title: "复制成功",
+        });
+      }
+      document.body.removeChild(textarea);
+    };
+    el.addEventListener("click", el.handler);
+  },
+  componentUpdated(el, { value }) {
+    el.$value = value;
+  },
+  unbind(el) {
+    el.removeEventListener("click", el.handler);
+  },
+};
+ + + + \ No newline at end of file diff --git a/Interview/index.html b/Interview/index.html new file mode 100644 index 00000000..8117dfc3 --- /dev/null +++ b/Interview/index.html @@ -0,0 +1,31 @@ + + + + + + 面试 | ZerDocs + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Problem/Graphical/Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.html" "b/Problem/Graphical/Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.html" new file mode 100644 index 00000000..1f4bcc63 --- /dev/null +++ "b/Problem/Graphical/Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.html" @@ -0,0 +1,1211 @@ + + + + + + 网络拓扑图代码 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

网络拓扑图代码

图实例化

js
import { commonRegister ,viewRegister} './registerElements.js'
+
+//1.初始化实例
+initChart() {
+  let halfWidth = this.width / 2;
+  let halfHeight = this.height / 2;
+  if (!this.graph) {
+    commonRegister()
+    viewRegister()
+    const toolbar = new G6.ToolBar({
+      position: { x: 10, y: 10 },
+      getContent: () => {
+         const outDiv = document.createElement('div');
+          let style = 'cursor: pointer;vertical-align: middle;line-height:24px;font-size:18px;'
+          outDiv.innerHTML = `<ul>
+              <li code='zoomOut' style="${style}" class="iconfont icon-fangda" title="放大"></li>
+              <li code='zoomIn'  style="${style}" class="iconfont icon-suoxiao" title="缩小"></li>
+              <li code='autoZoom' style="${style}" class="iconfont icon-fitscreen24" title="居中"></li>
+            </ul>`
+          return outDiv
+      },
+     handleClick: (code) => {
+          if (code === 'zoomOut') {
+             toolbar.zoomOut()
+          } else if (code === 'zoomIn') {
+             toolbar.zoomIn()
+          }else if(code === 'autoZoom'){
+             toolbar.autoZoom()
+          }
+        }
+    });
+    this.graph = new G6.Graph({
+      container: "topoChart",
+      width: this.width,
+      height: this.height,
+      fitView: true,
+      fitViewPadding: 100,
+      groupByTypes: false,
+      linkCenter: false,
+      layout: {
+        pipes: [
+          {
+            // 该子图所使用的布局类型
+            type: "circular",
+            center: [halfWidth, halfHeight],
+            radius: 80,
+            nodesFilter: (node) => node.sysType === "vpe",
+          },
+        ],
+      },
+      //交互行为相关配置
+      modes: {
+        default: ["drag-canvas", "zoom-canvas", {type: "drag-combo", shouldEnd(e, parent) {
+          if(parent) {
+            return false;
+          }
+          return true;
+        }}],
+      },
+      plugins: [toolbar],
+      defaultNode: {
+        type: "bubble",
+        labelCfg: {
+          position: "center",
+          style: {
+            fill: "white",
+            stroke: "#fff",
+          },
+        },
+      },
+      defaultEdge: {
+        color: "#888",
+        type: "animate-line",
+      },
+      defaultCombo: {
+        padding: 1,
+        style: {
+          cursor: "all-scroll",
+        },
+        labelCfg: {
+          style: {
+            opacity: 0,
+            fill: "#303133",
+            fontSize: 12,
+            stroke: "#fff",
+          },
+        },
+      },
+    });
+    //监听事件
+     this.graphBehaviors();
+  }
+},
+graphBehaviors(){
+    this.graph.on('node:click',this.debounce(this.eventHandle, 300));
+ //this.graph.on('edge:click'... 
+},
+debounce(fn, delay) {
+  const delays = delay || 300;
+  let timer;
+  return function() {
+    const th = this;
+    const args = arguments;
+    if (timer) {
+      clearTimeout(timer);
+    }
+    timer = setTimeout(function() {
+      timer = null;
+      fn.apply(th, args);
+    }, delays);
+  };
+},
+    //2.查询数据
+queryChartData(){
+    //处理数据
+    this.dealData(data)
+}
+//3.处理数据
+dealData(data ) {
+    //VPE节点
+    nodes =  ...
+    edges = ...
+    combos = ...
+    this.drawChart(...);
+}
+//4.渲染数据
+drawChart() {
+  this.graph.read({
+    nodes,
+    edges,
+    combos,
+  });
+},
import { commonRegister ,viewRegister} './registerElements.js'
+
+//1.初始化实例
+initChart() {
+  let halfWidth = this.width / 2;
+  let halfHeight = this.height / 2;
+  if (!this.graph) {
+    commonRegister()
+    viewRegister()
+    const toolbar = new G6.ToolBar({
+      position: { x: 10, y: 10 },
+      getContent: () => {
+         const outDiv = document.createElement('div');
+          let style = 'cursor: pointer;vertical-align: middle;line-height:24px;font-size:18px;'
+          outDiv.innerHTML = `<ul>
+              <li code='zoomOut' style="${style}" class="iconfont icon-fangda" title="放大"></li>
+              <li code='zoomIn'  style="${style}" class="iconfont icon-suoxiao" title="缩小"></li>
+              <li code='autoZoom' style="${style}" class="iconfont icon-fitscreen24" title="居中"></li>
+            </ul>`
+          return outDiv
+      },
+     handleClick: (code) => {
+          if (code === 'zoomOut') {
+             toolbar.zoomOut()
+          } else if (code === 'zoomIn') {
+             toolbar.zoomIn()
+          }else if(code === 'autoZoom'){
+             toolbar.autoZoom()
+          }
+        }
+    });
+    this.graph = new G6.Graph({
+      container: "topoChart",
+      width: this.width,
+      height: this.height,
+      fitView: true,
+      fitViewPadding: 100,
+      groupByTypes: false,
+      linkCenter: false,
+      layout: {
+        pipes: [
+          {
+            // 该子图所使用的布局类型
+            type: "circular",
+            center: [halfWidth, halfHeight],
+            radius: 80,
+            nodesFilter: (node) => node.sysType === "vpe",
+          },
+        ],
+      },
+      //交互行为相关配置
+      modes: {
+        default: ["drag-canvas", "zoom-canvas", {type: "drag-combo", shouldEnd(e, parent) {
+          if(parent) {
+            return false;
+          }
+          return true;
+        }}],
+      },
+      plugins: [toolbar],
+      defaultNode: {
+        type: "bubble",
+        labelCfg: {
+          position: "center",
+          style: {
+            fill: "white",
+            stroke: "#fff",
+          },
+        },
+      },
+      defaultEdge: {
+        color: "#888",
+        type: "animate-line",
+      },
+      defaultCombo: {
+        padding: 1,
+        style: {
+          cursor: "all-scroll",
+        },
+        labelCfg: {
+          style: {
+            opacity: 0,
+            fill: "#303133",
+            fontSize: 12,
+            stroke: "#fff",
+          },
+        },
+      },
+    });
+    //监听事件
+     this.graphBehaviors();
+  }
+},
+graphBehaviors(){
+    this.graph.on('node:click',this.debounce(this.eventHandle, 300));
+ //this.graph.on('edge:click'... 
+},
+debounce(fn, delay) {
+  const delays = delay || 300;
+  let timer;
+  return function() {
+    const th = this;
+    const args = arguments;
+    if (timer) {
+      clearTimeout(timer);
+    }
+    timer = setTimeout(function() {
+      timer = null;
+      fn.apply(th, args);
+    }, delays);
+  };
+},
+    //2.查询数据
+queryChartData(){
+    //处理数据
+    this.dealData(data)
+}
+//3.处理数据
+dealData(data ) {
+    //VPE节点
+    nodes =  ...
+    edges = ...
+    combos = ...
+    this.drawChart(...);
+}
+//4.渲染数据
+drawChart() {
+  this.graph.read({
+    nodes,
+    edges,
+    combos,
+  });
+},
js
mounted() {
+    this.chartLoading = true
+    this.width = document.getElementById("topoChart").scrollWidth;
+    this.height = document.getElementById("topoChart").scrollHeight || 600;
+    this.initChart();
+    this.queryChartData();
+    this.chartLoading = false
+    //监听窗口大小变化,重绘网络拓扑
+    window.addEventListener('resize',this.rePaint )
+  },
+beforeDestroy() {
+    if (this.graph) {
+      this.graph.clear();
+      this.graph.destroy();
+    }
+    this.data = Object.assign(this.$data, this.$options.data());
+},
mounted() {
+    this.chartLoading = true
+    this.width = document.getElementById("topoChart").scrollWidth;
+    this.height = document.getElementById("topoChart").scrollHeight || 600;
+    this.initChart();
+    this.queryChartData();
+    this.chartLoading = false
+    //监听窗口大小变化,重绘网络拓扑
+    window.addEventListener('resize',this.rePaint )
+  },
+beforeDestroy() {
+    if (this.graph) {
+      this.graph.clear();
+      this.graph.destroy();
+    }
+    this.data = Object.assign(this.$data, this.$options.data());
+},

注册节点

js
//registerElements.js
+import G6 from "@antv/g6";
+//共同节点注册
+export  function commonRegister(){
+  // 注册实线动画
+  G6.registerEdge("animate-line",
+    {
+      drawShape(cfg, group) {
+        const self = this;
+        let shapeStyle = self.getShapeStyle(cfg);
+        shapeStyle = Object.assign(shapeStyle, {
+          opacity: 0,
+          strokeOpacity: 0,
+        });
+        const keyShape = group.addShape("path", {
+          attrs: shapeStyle,
+          name: "path-shape",
+        });
+        return keyShape;
+      },
+      afterDraw(cfg, group) {
+        const shape = group.get("children")[0];
+        //线条动画
+        shape.animate(
+          (ratio) => {
+            const opacity = ratio * cfg.style.opacity;
+            const strokeOpacity = ratio * cfg.style.strokeOpacity;
+            return {
+              opacity: ratio || opacity,
+              strokeOpacity: ratio || strokeOpacity,
+            };
+          },
+          {
+            duration: 300,
+          }
+        );
+        //箭头动画
+        const startPoint = shape.getPoint(0);
+        const circle = group.addShape("circle", {
+          attrs: {
+            x: startPoint.x,
+            y: startPoint.y,
+            fill: "#1890ff",
+            r: 2,
+          },
+          name: "circle-shape",
+        });
+        circle.animate(
+          (ratio) => {
+            const tmpPoint = shape.getPoint(ratio);
+            return {
+              x: tmpPoint.x,
+              y: tmpPoint.y,
+            };
+          },
+          {
+            repeat: true,
+            duration: 3000,
+          }
+        );
+      },
+      setState(name, value, item) {
+        const shape = item.get("keyShape");
+        if (name === "disappearing" && value) {
+          shape.animate(
+            (ratio) => {
+              return {
+                opacity: 1 - ratio,
+                strokeOpacity: 1 - ratio,
+              };
+            },
+            {
+              duration: 200,
+            }
+          );
+        } else if (name === "dark") {
+          if (value) shape.attr("opacity", 0.2);
+          else shape.attr("opacity", 1);
+        }
+      },
+    },
+    "line"
+  );
+  //注册iconfont节点
+  G6.registerNode("iconfontHub", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle ,size } = cfg;
+      group.addShape("circle", {
+        attrs: {
+          x: 0,
+          y: size / 2,
+          r: size,
+        },
+        name: "hub-bg-shape",
+      });
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: size  / 2,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          text: cfg.text,
+          fontSize: Math.round(size),
+          ...style,
+        },
+        name: "hub-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: Math.round(size/4),
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "hub-label",
+      });
+      return keyShape;
+    },
+    // afterDraw(cfg, group) {
+    //   const shape = group.get('children')[0];
+    //   shape.animate(
+    //     (ratio) => {
+    //       let fill = '#C396ED'
+    //       if(ratio > 0.6){
+    //         fill = '#FFCF8B'
+    //       }else if(ratio > 0.3){
+    //         fill = '#C396ED'
+    //       }else {
+    //         fill = '#75D882'
+    //       }
+    //       return {
+    //         fill,
+    //       };
+    //     },
+    //     {
+    //       repeat: true,
+    //       duration: 1500,
+    //       // easing: 'easeCubic',
+    //     },
+    //   );
+    // },
+  });
+  //自定义节点和节点动画
+  G6.registerNode( "vpe-rect-animate",
+    {
+    afterDraw(cfg, group) {
+      const { width, height, stroke, radius } = this.getShapeStyle(cfg);
+      const x = -width / 2,
+        y = -height / 2;
+      const back1 = group.addShape("rect", {
+        zIndex: -3,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback1-shape",
+      });
+      const back2 = group.addShape("rect", {
+        zIndex: -2,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback2-shape",
+      });
+      const back3 = group.addShape("circle", {
+        zIndex: -1,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback3-shape",
+      });
+      group.sort(); // Sort according to the zIndex
+      back1.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: -300,
+          repeat: true, // repeat
+        }
+      ); // no delay
+      back2.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 1000,
+          repeat: true,  
+        }
+      );  
+      back3.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 2000,
+          repeat: true, // repeat
+        }
+      ); // 3s delay
+    },
+  },
+  "rect"
+);
+}
+//弹窗特有节点注册
+export function dialogRegister(){
+   //注册iconfont节点
+   G6.registerNode("iconfontCpe", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle } = cfg;
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 0,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.text,
+          fontSize: cfg.size,
+          ...style,
+        },
+        name: "cpe-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 10,
+          textAlign: "center",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "cpe-label",
+      });
+  
+      return keyShape;
+    },
+    afterDraw(cfg, group) {
+      const shape = group.get('children')[0];
+      shape.animate(
+        (ratio) => {
+          let text = '\ue604'
+          if(ratio > 0.6){
+            text = '\ue604'
+          }else if(ratio > 0.3){
+            text = '\ue606'
+          }else {
+            text = '\ue605'
+          }
+          return {
+            text,
+          };
+        },
+        {
+          repeat: true,
+          duration: 1500,
+          delay: 3000,
+          // easing: 'easeCubic',
+        },
+      );
+    },
+  });
+  //注册虚线动画
+  // G6.registerEdge("vpn-line-dash",
+  //   {
+  //     afterDraw(cfg, group) {
+  //       const shape = group.get("children")[0];
+  //       let index = 0;
+  //       shape.animate(
+  //         () => {
+  //           index = index+0.2;
+  //           if (index > 9) {
+  //             index = 0;
+  //           }
+  //           const res = {
+  //             lineDash: [4, 4],
+  //             lineDashOffset: -index,
+  //           };
+  //           return res;
+  //         },
+  //         {
+  //           repeat: true,
+  //           duration:10000,
+  //         }
+  //       );
+  //     },
+  //   },
+  //   "line"
+  // );
+}
+
+//网络拓扑总览特有节点注册
+export function viewRegister(){
+  //注册iconfont combos
+  // G6.registerCombo("cloudCombo",
+  //   {
+  //     drawShape: function drawShape(cfg, group) {
+  //       // const {  labelCfg: labelStyle   } = cfg;
+  //       const keyShape = group.addShape("text", { 
+  //         attrs: {
+  //           y: 0,
+  //           x: 0,
+  //           fill: cfg.style.fill,
+  //           stroke: cfg.style.fill,
+  //           fontFamily: "iconfont",
+  //           textAlign: "center",
+  //           textBaseline: "middle",
+  //           text: "\ue603",
+  //           fontSize: 320,
+  //           zIndex: 8,
+  //         },
+  //         name: "cloud",
+  //       });
+  //           //添加label
+  //     // group.addShape("text", {
+  //     //   attrs: {
+  //     //     x: 0,
+  //     //     y: -80,
+  //     //     textAlign: "center",
+  //     //     textBaseline: "middle",
+  //     //     text: cfg.label,
+  //     //     ...labelStyle.style,
+  //     //   },
+  //     //   name: "hubCombo-label",
+  //     // });
+  //       return keyShape;
+  //     },
+  //   },
+  //   "cicle"
+  // );
+    //注册SVG combo
+  G6.registerCombo(
+      "cloudCombo",
+      {
+        drawShape: function drawShape(cfg, group) {
+          const { labelCfg  } = cfg;
+          let str = 'M 448 102.875 c 0 -82.09 -56.678 -150.9 -132.996 -169.48 C 311.762 -195.305 206.546 -298.667 77.142 -298.667 c -75.792 0 -143.266 35.494 -186.854 90.732 c -24.442 -31.598 -62.69 -51.96 -105.708 -51.96 c -73.81 0 -133.642 59.874 -133.642 133.722 c 0 6.436 0.48 12.76 1.364 18.954 c -11.222 -2.024 -22.766 -3.138 -34.57 -3.138 C -489.266 -110.359 -576 -23.5707 -576 83.4853 C -576 190.547 -489.266 277.333 -382.27 277.333 l 656.262 0 l 0 -0.012 C 370.13 277.137 448 199.109 448 102.875 Z'
+            const pathArr =str.split(' ');
+            let opath = []
+            pathArr.forEach(item => {
+              if(/[a-zA-Z]/.test(item)){
+              opath.push([item])
+            }else {
+              opath[opath.length - 1].push(parseFloat(item))
+            }
+            });
+
+          opath.forEach(item => {
+            item.forEach((p,i) => {
+              if (i > 0) {
+                item [i] = item[i] / 3  ;
+              }
+            });
+          });
+          const keyShape = group.addShape("path", {
+            attrs: {
+              ...cfg.style,
+              width: cfg.style.width,
+              height: cfg.style.height,
+              path:  opath,
+            },
+            id: cfg.id,
+            name: "cloud",
+          });
+          group.addShape("text", {
+            attrs: {
+              x: 0,
+              y:  -100,
+              textAlign: "center",
+              text: cfg.label,
+              fill: '#303133',
+            },
+            name: "hubCombo-label",
+          });
+          return keyShape;
+        },
+        
+      },
+      "single-combo"
+    );
+   
+}
+
+ //节点文本溢出省略处理
+ export function fittingString(str, maxWidth, fontSize){
+  const ellipsis = '...';
+  const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
+  let currentWidth = 0;
+  let res = str;
+  const pattern = new RegExp('[\u4E00-\u9FA5]+');  
+  str.split('').forEach((letter, i) => {
+    if (currentWidth > maxWidth - ellipsisLength) return;
+    if (pattern.test(letter)) {
+      currentWidth += fontSize;
+    } else {
+      currentWidth += G6.Util.getLetterWidth(letter, fontSize);
+    }
+    if (currentWidth > maxWidth - ellipsisLength) {
+      res = `${str.substr(0, i)}${ellipsis}`;
+    }
+  });
+  return res;
+}
//registerElements.js
+import G6 from "@antv/g6";
+//共同节点注册
+export  function commonRegister(){
+  // 注册实线动画
+  G6.registerEdge("animate-line",
+    {
+      drawShape(cfg, group) {
+        const self = this;
+        let shapeStyle = self.getShapeStyle(cfg);
+        shapeStyle = Object.assign(shapeStyle, {
+          opacity: 0,
+          strokeOpacity: 0,
+        });
+        const keyShape = group.addShape("path", {
+          attrs: shapeStyle,
+          name: "path-shape",
+        });
+        return keyShape;
+      },
+      afterDraw(cfg, group) {
+        const shape = group.get("children")[0];
+        //线条动画
+        shape.animate(
+          (ratio) => {
+            const opacity = ratio * cfg.style.opacity;
+            const strokeOpacity = ratio * cfg.style.strokeOpacity;
+            return {
+              opacity: ratio || opacity,
+              strokeOpacity: ratio || strokeOpacity,
+            };
+          },
+          {
+            duration: 300,
+          }
+        );
+        //箭头动画
+        const startPoint = shape.getPoint(0);
+        const circle = group.addShape("circle", {
+          attrs: {
+            x: startPoint.x,
+            y: startPoint.y,
+            fill: "#1890ff",
+            r: 2,
+          },
+          name: "circle-shape",
+        });
+        circle.animate(
+          (ratio) => {
+            const tmpPoint = shape.getPoint(ratio);
+            return {
+              x: tmpPoint.x,
+              y: tmpPoint.y,
+            };
+          },
+          {
+            repeat: true,
+            duration: 3000,
+          }
+        );
+      },
+      setState(name, value, item) {
+        const shape = item.get("keyShape");
+        if (name === "disappearing" && value) {
+          shape.animate(
+            (ratio) => {
+              return {
+                opacity: 1 - ratio,
+                strokeOpacity: 1 - ratio,
+              };
+            },
+            {
+              duration: 200,
+            }
+          );
+        } else if (name === "dark") {
+          if (value) shape.attr("opacity", 0.2);
+          else shape.attr("opacity", 1);
+        }
+      },
+    },
+    "line"
+  );
+  //注册iconfont节点
+  G6.registerNode("iconfontHub", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle ,size } = cfg;
+      group.addShape("circle", {
+        attrs: {
+          x: 0,
+          y: size / 2,
+          r: size,
+        },
+        name: "hub-bg-shape",
+      });
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: size  / 2,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          text: cfg.text,
+          fontSize: Math.round(size),
+          ...style,
+        },
+        name: "hub-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: Math.round(size/4),
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "hub-label",
+      });
+      return keyShape;
+    },
+    // afterDraw(cfg, group) {
+    //   const shape = group.get('children')[0];
+    //   shape.animate(
+    //     (ratio) => {
+    //       let fill = '#C396ED'
+    //       if(ratio > 0.6){
+    //         fill = '#FFCF8B'
+    //       }else if(ratio > 0.3){
+    //         fill = '#C396ED'
+    //       }else {
+    //         fill = '#75D882'
+    //       }
+    //       return {
+    //         fill,
+    //       };
+    //     },
+    //     {
+    //       repeat: true,
+    //       duration: 1500,
+    //       // easing: 'easeCubic',
+    //     },
+    //   );
+    // },
+  });
+  //自定义节点和节点动画
+  G6.registerNode( "vpe-rect-animate",
+    {
+    afterDraw(cfg, group) {
+      const { width, height, stroke, radius } = this.getShapeStyle(cfg);
+      const x = -width / 2,
+        y = -height / 2;
+      const back1 = group.addShape("rect", {
+        zIndex: -3,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback1-shape",
+      });
+      const back2 = group.addShape("rect", {
+        zIndex: -2,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback2-shape",
+      });
+      const back3 = group.addShape("circle", {
+        zIndex: -1,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback3-shape",
+      });
+      group.sort(); // Sort according to the zIndex
+      back1.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: -300,
+          repeat: true, // repeat
+        }
+      ); // no delay
+      back2.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 1000,
+          repeat: true,  
+        }
+      );  
+      back3.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 2000,
+          repeat: true, // repeat
+        }
+      ); // 3s delay
+    },
+  },
+  "rect"
+);
+}
+//弹窗特有节点注册
+export function dialogRegister(){
+   //注册iconfont节点
+   G6.registerNode("iconfontCpe", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle } = cfg;
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 0,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.text,
+          fontSize: cfg.size,
+          ...style,
+        },
+        name: "cpe-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 10,
+          textAlign: "center",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "cpe-label",
+      });
+  
+      return keyShape;
+    },
+    afterDraw(cfg, group) {
+      const shape = group.get('children')[0];
+      shape.animate(
+        (ratio) => {
+          let text = '\ue604'
+          if(ratio > 0.6){
+            text = '\ue604'
+          }else if(ratio > 0.3){
+            text = '\ue606'
+          }else {
+            text = '\ue605'
+          }
+          return {
+            text,
+          };
+        },
+        {
+          repeat: true,
+          duration: 1500,
+          delay: 3000,
+          // easing: 'easeCubic',
+        },
+      );
+    },
+  });
+  //注册虚线动画
+  // G6.registerEdge("vpn-line-dash",
+  //   {
+  //     afterDraw(cfg, group) {
+  //       const shape = group.get("children")[0];
+  //       let index = 0;
+  //       shape.animate(
+  //         () => {
+  //           index = index+0.2;
+  //           if (index > 9) {
+  //             index = 0;
+  //           }
+  //           const res = {
+  //             lineDash: [4, 4],
+  //             lineDashOffset: -index,
+  //           };
+  //           return res;
+  //         },
+  //         {
+  //           repeat: true,
+  //           duration:10000,
+  //         }
+  //       );
+  //     },
+  //   },
+  //   "line"
+  // );
+}
+
+//网络拓扑总览特有节点注册
+export function viewRegister(){
+  //注册iconfont combos
+  // G6.registerCombo("cloudCombo",
+  //   {
+  //     drawShape: function drawShape(cfg, group) {
+  //       // const {  labelCfg: labelStyle   } = cfg;
+  //       const keyShape = group.addShape("text", { 
+  //         attrs: {
+  //           y: 0,
+  //           x: 0,
+  //           fill: cfg.style.fill,
+  //           stroke: cfg.style.fill,
+  //           fontFamily: "iconfont",
+  //           textAlign: "center",
+  //           textBaseline: "middle",
+  //           text: "\ue603",
+  //           fontSize: 320,
+  //           zIndex: 8,
+  //         },
+  //         name: "cloud",
+  //       });
+  //           //添加label
+  //     // group.addShape("text", {
+  //     //   attrs: {
+  //     //     x: 0,
+  //     //     y: -80,
+  //     //     textAlign: "center",
+  //     //     textBaseline: "middle",
+  //     //     text: cfg.label,
+  //     //     ...labelStyle.style,
+  //     //   },
+  //     //   name: "hubCombo-label",
+  //     // });
+  //       return keyShape;
+  //     },
+  //   },
+  //   "cicle"
+  // );
+    //注册SVG combo
+  G6.registerCombo(
+      "cloudCombo",
+      {
+        drawShape: function drawShape(cfg, group) {
+          const { labelCfg  } = cfg;
+          let str = 'M 448 102.875 c 0 -82.09 -56.678 -150.9 -132.996 -169.48 C 311.762 -195.305 206.546 -298.667 77.142 -298.667 c -75.792 0 -143.266 35.494 -186.854 90.732 c -24.442 -31.598 -62.69 -51.96 -105.708 -51.96 c -73.81 0 -133.642 59.874 -133.642 133.722 c 0 6.436 0.48 12.76 1.364 18.954 c -11.222 -2.024 -22.766 -3.138 -34.57 -3.138 C -489.266 -110.359 -576 -23.5707 -576 83.4853 C -576 190.547 -489.266 277.333 -382.27 277.333 l 656.262 0 l 0 -0.012 C 370.13 277.137 448 199.109 448 102.875 Z'
+            const pathArr =str.split(' ');
+            let opath = []
+            pathArr.forEach(item => {
+              if(/[a-zA-Z]/.test(item)){
+              opath.push([item])
+            }else {
+              opath[opath.length - 1].push(parseFloat(item))
+            }
+            });
+
+          opath.forEach(item => {
+            item.forEach((p,i) => {
+              if (i > 0) {
+                item [i] = item[i] / 3  ;
+              }
+            });
+          });
+          const keyShape = group.addShape("path", {
+            attrs: {
+              ...cfg.style,
+              width: cfg.style.width,
+              height: cfg.style.height,
+              path:  opath,
+            },
+            id: cfg.id,
+            name: "cloud",
+          });
+          group.addShape("text", {
+            attrs: {
+              x: 0,
+              y:  -100,
+              textAlign: "center",
+              text: cfg.label,
+              fill: '#303133',
+            },
+            name: "hubCombo-label",
+          });
+          return keyShape;
+        },
+        
+      },
+      "single-combo"
+    );
+   
+}
+
+ //节点文本溢出省略处理
+ export function fittingString(str, maxWidth, fontSize){
+  const ellipsis = '...';
+  const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
+  let currentWidth = 0;
+  let res = str;
+  const pattern = new RegExp('[\u4E00-\u9FA5]+');  
+  str.split('').forEach((letter, i) => {
+    if (currentWidth > maxWidth - ellipsisLength) return;
+    if (pattern.test(letter)) {
+      currentWidth += fontSize;
+    } else {
+      currentWidth += G6.Util.getLetterWidth(letter, fontSize);
+    }
+    if (currentWidth > maxWidth - ellipsisLength) {
+      res = `${str.substr(0, i)}${ellipsis}`;
+    }
+  });
+  return res;
+}
+ + + + \ No newline at end of file diff --git "a/Problem/Graphical/Antv\344\275\277\347\224\250\346\200\273\347\273\223.html" "b/Problem/Graphical/Antv\344\275\277\347\224\250\346\200\273\347\273\223.html" new file mode 100644 index 00000000..798b13d4 --- /dev/null +++ "b/Problem/Graphical/Antv\344\275\277\347\224\250\346\200\273\347\273\223.html" @@ -0,0 +1,55 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

一、默认收缩二级节点

js
//树形图哪个需要收缩则把属性collapsed设置为true
+data.children.forEach(item => item.collapsed = true)
//树形图哪个需要收缩则把属性collapsed设置为true
+data.children.forEach(item => item.collapsed = true)

二、改用iconfont文字不居中问题

js
//注册节点添加label图形时动态计算label位置
+ group.addShape("text", {
+   attrs: {
+     x: 0,
+     y: -80,
+   textAlign: "center",
+   textBaseline: "middle",
+    text: cfg.label,
+   ...labelStyle.style,//这里需要重新处理x,y
+ },
+  name: "hubCombo-label",
+});
//注册节点添加label图形时动态计算label位置
+ group.addShape("text", {
+   attrs: {
+     x: 0,
+     y: -80,
+   textAlign: "center",
+   textBaseline: "middle",
+    text: cfg.label,
+   ...labelStyle.style,//这里需要重新处理x,y
+ },
+  name: "hubCombo-label",
+});

三、初始化画图完成后出现这个锯齿

+ + + + \ No newline at end of file diff --git "a/Problem/Graphical/Echarts\351\227\256\351\242\230\346\200\273\347\273\223.html" "b/Problem/Graphical/Echarts\351\227\256\351\242\230\346\200\273\347\273\223.html" new file mode 100644 index 00000000..6fe19b10 --- /dev/null +++ "b/Problem/Graphical/Echarts\351\227\256\351\242\230\346\200\273\347\273\223.html" @@ -0,0 +1,249 @@ + + + + + + Echarts问题总结 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Echarts问题总结

屏幕适配问题

方案一: 使用scss函数计算比例

scss
//默认设计稿的宽度
+$designWidth:1920;
+//默认设计稿的高度
+$designHeight:1080;
+
+//px转为vw的函数
+@function vw($px) {
+  @return math.div($px , $designWidth) * 100vw;
+}
+
+//px转为vh的函数
+@function vh($px) {
+  @return math.div($px , $designHeight) * 100vh;
+}
//默认设计稿的宽度
+$designWidth:1920;
+//默认设计稿的高度
+$designHeight:1080;
+
+//px转为vw的函数
+@function vw($px) {
+  @return math.div($px , $designWidth) * 100vw;
+}
+
+//px转为vh的函数
+@function vh($px) {
+  @return math.div($px , $designHeight) * 100vh;
+}

左侧菜单折叠响应式

js
 mounted() {
+// 监听窗口大小,所有echart实例尺寸尺寸改变
+    window.addEventListener("resize", () => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    });
+  //监听div容器的无效
+   /*this.$refs.onlineIspRef.addEventListener("resize",() => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    })*/
+}
 mounted() {
+// 监听窗口大小,所有echart实例尺寸尺寸改变
+    window.addEventListener("resize", () => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    });
+  //监听div容器的无效
+   /*this.$refs.onlineIspRef.addEventListener("resize",() => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    })*/
+}

方案: 侧边栏按钮点击展开/折叠时, 手动触发window.resize

js
 toggleLeftMenu() {
+      Cookies.set('sidebar', this.leftMenuOpen ? 'close' : 'open', {path: '/'});
+      this.$store.commit('toggleLeftMenu', !this.leftMenuOpen);
+      this.doResize()
+  },
+doResize(){ 
+    setTimeout(function(){
+          var ev = new Event("resize", {"bubbles":true, "cancelable":false});
+          window.dispatchEvent(ev);
+      },120);//不使用定时器没反应
+    
+    //有效, 而且提示event.initEvent方法已经过时(deprecated)
+    //但是折线图左侧收缩/延伸会有抖动问题,需要调节定时器时间使比较不突兀
+  /*setTimeout(function(){
+      if(document.createEvent) {
+          var event = document.createEvent("HTMLEvents");
+          event.initEvent("resize", true, true);
+          window.dispatchEvent(event);
+      } else if(document.createEventObject) {
+          window.fireEvent("onresize");
+      }
+  },120);*/
+    
+},
 toggleLeftMenu() {
+      Cookies.set('sidebar', this.leftMenuOpen ? 'close' : 'open', {path: '/'});
+      this.$store.commit('toggleLeftMenu', !this.leftMenuOpen);
+      this.doResize()
+  },
+doResize(){ 
+    setTimeout(function(){
+          var ev = new Event("resize", {"bubbles":true, "cancelable":false});
+          window.dispatchEvent(ev);
+      },120);//不使用定时器没反应
+    
+    //有效, 而且提示event.initEvent方法已经过时(deprecated)
+    //但是折线图左侧收缩/延伸会有抖动问题,需要调节定时器时间使比较不突兀
+  /*setTimeout(function(){
+      if(document.createEvent) {
+          var event = document.createEvent("HTMLEvents");
+          event.initEvent("resize", true, true);
+          window.dispatchEvent(event);
+      } else if(document.createEventObject) {
+          window.fireEvent("onresize");
+      }
+  },120);*/
+    
+},

地图缩放重叠问题

Echart文档参考

js
export default {
+	geo: {
+		roam: true,
+		map: "china",
+		aspectScale: 0.75,  
+		zoom: 1.1,
+		itemStyle: {
+			normal: {
+				shadowColor: "#ddd",
+				shadowOffsetX: 5,
+				shadowOffsetY: 5,
+			},
+		},
+		regions: [
+			{
+				name: "南海诸岛",
+				itemStyle: {
+					areaColor: "rgba(0, 10, 52, 1)",
+					borderColor: "rgba(0, 10, 52, 1)",
+					normal: {
+						opacity: 0,
+						label: {
+							show: false,
+							color: "#009cc9",
+						},
+					},
+				},
+			},
+		],
+	},
+	series: [
+		{
+			type: "map",
+			geoIndex: 0, //方案一:设置这个属性
+			label: {
+				normal: {
+					show: true,
+					textStyle: {
+						color: "#666",
+					},
+				},
+				emphasis: {
+					textStyle: {
+						color: "#fff",  
+					},
+				},
+			},
+			itemStyle: {
+				normal: {
+					borderType: "dashed",
+				},
+				emphasis: {
+					areaColor: "#3777DD",
+					borderWidth: 0.1,
+				},
+			},
+			zoom: 1.1,
+			map: "china", // //方案二:删除这个属性
+		},
+	],
+}
export default {
+	geo: {
+		roam: true,
+		map: "china",
+		aspectScale: 0.75,  
+		zoom: 1.1,
+		itemStyle: {
+			normal: {
+				shadowColor: "#ddd",
+				shadowOffsetX: 5,
+				shadowOffsetY: 5,
+			},
+		},
+		regions: [
+			{
+				name: "南海诸岛",
+				itemStyle: {
+					areaColor: "rgba(0, 10, 52, 1)",
+					borderColor: "rgba(0, 10, 52, 1)",
+					normal: {
+						opacity: 0,
+						label: {
+							show: false,
+							color: "#009cc9",
+						},
+					},
+				},
+			},
+		],
+	},
+	series: [
+		{
+			type: "map",
+			geoIndex: 0, //方案一:设置这个属性
+			label: {
+				normal: {
+					show: true,
+					textStyle: {
+						color: "#666",
+					},
+				},
+				emphasis: {
+					textStyle: {
+						color: "#fff",  
+					},
+				},
+			},
+			itemStyle: {
+				normal: {
+					borderType: "dashed",
+				},
+				emphasis: {
+					areaColor: "#3777DD",
+					borderWidth: 0.1,
+				},
+			},
+			zoom: 1.1,
+			map: "china", // //方案二:删除这个属性
+		},
+	],
+}
+ + + + \ No newline at end of file diff --git "a/Problem/Nuxt3/Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.html" "b/Problem/Nuxt3/Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.html" new file mode 100644 index 00000000..344905c9 --- /dev/null +++ "b/Problem/Nuxt3/Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.html" @@ -0,0 +1,103 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Uncaught TypeError: Cannot read properties of undefined (reading 'prototype')

2023-05-19-14-49-43

js
//uno.config.ts
+shortcuts: [["f-s-c", "flex justify-start items-center"]];
//uno.config.ts
+shortcuts: [["f-s-c", "flex justify-start items-center"]];
  1. 写在类名上不生效
html
<!--f-s-c 直接写在类名上不生效-->
+<div class="hidden lg:f-c-c">Test</div>
<!--f-s-c 直接写在类名上不生效-->
+<div class="hidden lg:f-c-c">Test</div>
  1. 写在 CSS 上报错
html
<div class="nav">Test</div>
<div class="nav">Test</div>
css
// f-s-c 报错;The `xl:f-c-c` class does not exist. If `xl:f-c-c` is a custom class, make sure it is defined within a `@layer` directive.
+
+.nav {
+  @apply hidden lg:f-c-c;
+}
// f-s-c 报错;The `xl:f-c-c` class does not exist. If `xl:f-c-c` is a custom class, make sure it is defined within a `@layer` directive.
+
+.nav {
+  @apply hidden lg:f-c-c;
+}

解决方法:断点后不写自定义的

html
<div class="hidden lg:flex justify-center items-center">Test</div>
<div class="hidden lg:flex justify-center items-center">Test</div>

总结:自定义的类名快捷键不能写在变体后面

hidden 与自定义变体不能一起用

ts
//uno.config.ts
+shortcuts: [
+  ["f-s-c", "flex justify-start items-center"],
+  ["f-c-c", "flex justify-center items-center"],
+];
//uno.config.ts
+shortcuts: [
+  ["f-s-c", "flex justify-start items-center"],
+  ["f-c-c", "flex justify-center items-center"],
+];
html
<div class="hidden xl:f-c-c">TEST</div>
<div class="hidden xl:f-c-c">TEST</div>

可以这样用

html
<div class="f-s-c xl:f-c-c">TEST</div>
<div class="f-s-c xl:f-c-c">TEST</div>

项目一直报 Element 相关错误

element-ui.js:1 Uncaught TypeError: Cannot read properties of undefined (reading 'prototype')2023-05-21-20-26-38 换浏览器后没报错,定位到可能是浏览器插件的原因,果然排除法找到是:YouTube 视频摘要 ChatGPT 生成-快速笔记 (中文版) 的问题!

跨域问题

js
export default defineNuxtConfig({
+  /* ... */
+  nitro: {
+    devProxy: {
+      '/account/api': {
+        target: 'http://192.168.211.63/account/api',
+       // target: 'http://192.168.211.63', 【不生效】 不同于 vite,这样配置到达 nginx 是 '/'
+        ws: false,
+        changeOrigin: true,
+      },
+    },
+  }
+})
export default defineNuxtConfig({
+  /* ... */
+  nitro: {
+    devProxy: {
+      '/account/api': {
+        target: 'http://192.168.211.63/account/api',
+       // target: 'http://192.168.211.63', 【不生效】 不同于 vite,这样配置到达 nginx 是 '/'
+        ws: false,
+        changeOrigin: true,
+      },
+    },
+  }
+})
js
//业务请求
+async function getImgCode() {
+  const data = await useFetch('/account/api/getImageCode', {
+    method: 'POST',
+    body:{},
+  })
+  return data.data.value
+}
//业务请求
+async function getImgCode() {
+  const data = await useFetch('/account/api/getImageCode', {
+    method: 'POST',
+    body:{},
+  })
+  return data.data.value
+}

nuxt-simple-sitemap插件使用问题

打包时报错:解析到错误 URL

js
nitro: {
+    prerender: {
+      crawlLinks: true,
+      routes: ['/'], //去掉: ,'sitemap.xml'
+    },
+}
nitro: {
+    prerender: {
+      crawlLinks: true,
+      routes: ['/'], //去掉: ,'sitemap.xml'
+    },
+}

测试环境能访问sitemap.xml 页面 但是线上环境访问不到,报相关错误:/__sitemap__/routes.json ,需要在 nginx 配置 IP 和主机名的传送。

zsh
  # nginx.conf
+   proxy_set_header X-Real-IP $remote_addr;
+   proxy_set_header Host $host;
  # nginx.conf
+   proxy_set_header X-Real-IP $remote_addr;
+   proxy_set_header Host $host;
+ + + + \ No newline at end of file diff --git "a/Problem/VitePress/VitePress\350\270\251\345\235\221\350\256\260\345\275\225.html" "b/Problem/VitePress/VitePress\350\270\251\345\235\221\350\256\260\345\275\225.html" new file mode 100644 index 00000000..7a4d1047 --- /dev/null +++ "b/Problem/VitePress/VitePress\350\270\251\345\235\221\350\256\260\345\275\225.html" @@ -0,0 +1,337 @@ + + + + + + VitePress踩坑记录 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

VitePress踩坑记录

ERR_INVALID_FILE_URL_HOST

DANGER

执行打包命令时,出现此错误 TypeError [ERR_INVALID_FILE_URL_HOST]: File URL host must be "localhost" or empty on darwin

形成原因:全局替换时粗心大意造成img src属性多了个'/'

解决

TIP

刚开始我只能猜到某个文件路径有问题 ,又不知道那个文件有问题,最后用上了 排除法 逐个移除文章文件夹最终才定位到出问题的文档。 虽然问题解决的的过程有点费劲,不得不说当问题搞得人想撞墙的时候,无疑也是一个不错的思路和方法!!!

删除多余的'/'就好了,自己解决自己的 issues !!!

实现自动生成文章左侧侧边栏

痛点及需求

WARNING

​ 每次添加文章过程:对应的目录下添加.md文, 修改themeConfig的sidebar属性,给对象加上新增的文章映射

​ 添加的文章少还好,多了的话就显得很麻烦不够优雅,所有想写个脚本按照目录结构自动生产对应的映射关系。

想法及实现

在package.json添加脚本执行命令

image-20230205230548188

在博客根目录新建scripts目录并创建文件getSidebar.ts,添加如下代码

js
/********   读取 zerdocs/docs/ 下的所有文件夹,自动生成侧边栏sidebar.ts文件   ***********/
+
+
+const fs = require('fs')
+const path = require('path')
+
+let sidebarObj = {}
+
+//生成一级分组 
+let topDirArr = fs.readdirSync(path.resolve(__dirname, '../docs')).filter((item) => isArticleDir(item))
+topDirArr.forEach((item) => {
+  if (!sidebarObj[`/${item}/`]) {
+    sidebarObj[`/${item}/`] = []
+  }
+})
+
+const sidebars = deepGetFile(path.resolve(__dirname, '../docs')) // 读取 docs 目录下的所有文件夹
+const sidebarlist = deepGenerateSidebar(sidebars)
+
+//写入到docs/.vitepress/sidebar/index.ts
+
+//把数组里面的每个对象合并到一个对象里面
+let sidebar = sidebarlist.reduce((pre, cur) => Object.assign(pre, cur), {})
+Object.entries(sidebar).forEach(([key, items]) => {
+  let keyArr = splitPath(key)
+  let text = keyArr[keyArr.length - 1]
+  if(sidebarObj[`/${keyArr[0]}/`]){
+    sidebarObj[`/${keyArr[0]}/`].push({
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    })
+  }else{
+    sidebarObj[`/${keyArr[0]}/`] = [{
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    }]
+  }
+})
+
+const sidebarStr = JSON.stringify(sidebarObj, null, 2)
+//把sidebarStr写入到docs/.vitepress/sidebar/index.ts
+const sidebarPath = path.resolve(__dirname, '../docs/.vitepress/sidebar/index.ts')
+
+//没有则创建
+if (!fs.existsSync(sidebarPath)) {
+  fs.mkdirSync(path.resolve(__dirname, '../docs/.vitepress/sidebar'))
+}
+
+fs.writeFileSync(sidebarPath, `export default ${sidebarStr}`)
+
+//判断是否是文件夹
+function isArticleDir(dir) {
+  let exclude = ['public', 'index.md','vite.config.ts']  //排除的文件夹
+  return !exclude.includes(dir) && !dir.startsWith('.')
+}
+
+function splitPath(path) {
+  return path.split('/').filter((item) => item !== '')
+}
+function deepGetFile(dir) {
+  let backList = []
+  let list = fs.readdirSync(dir).filter((item) => isArticleDir(item))
+
+  for (let index in list) {
+    let item = path.resolve(dir, list[index])
+    if (fs.statSync(item).isDirectory()) {
+      backList = backList.concat(deepGetFile(item))
+    } else {
+      //输出相对路径
+      item = item.replace(path.resolve(__dirname, '../docs'), '').replace(/\\/g, '/')
+      backList.push(item)
+    }
+  }
+  return backList
+}
+
+// 生成侧边栏
+function deepGenerateSidebar(arr) {
+  //递归按照最后一级目录生成侧边栏
+  const sidebar = {}
+  sidebars.forEach((item) => {
+    const [dir, ...rest] = splitPath(item)
+    if (!sidebar[dir]) {
+      sidebar[dir] = []
+    }
+    sidebar[dir].push(item)
+  })
+  let sidebarList = []
+  //按最后一级目录分组
+  for (let key in sidebar) {
+    let pathPice = sidebar[key].map((item) => splitPath(item))
+    //如果pathPice[pathPice.length-1]相同,则合并
+    pathPice = pathPice.reduce((pre, cur) => {
+      let dirStr = cur.slice(0, -1).join('/') // /problem/vueproject/
+      let text = cur[cur.length - 1].replace(/\.md$/, '')
+      let link = '/' + cur.join('/').replace(/\.md$/, '')
+      pre[dirStr] = pre[dirStr] ? [...pre[dirStr], { text, link }] : [{ text, link }]
+      return pre
+    }, {})
+    sidebarList.push(pathPice)
+  }
+  return sidebarList
+}
/********   读取 zerdocs/docs/ 下的所有文件夹,自动生成侧边栏sidebar.ts文件   ***********/
+
+
+const fs = require('fs')
+const path = require('path')
+
+let sidebarObj = {}
+
+//生成一级分组 
+let topDirArr = fs.readdirSync(path.resolve(__dirname, '../docs')).filter((item) => isArticleDir(item))
+topDirArr.forEach((item) => {
+  if (!sidebarObj[`/${item}/`]) {
+    sidebarObj[`/${item}/`] = []
+  }
+})
+
+const sidebars = deepGetFile(path.resolve(__dirname, '../docs')) // 读取 docs 目录下的所有文件夹
+const sidebarlist = deepGenerateSidebar(sidebars)
+
+//写入到docs/.vitepress/sidebar/index.ts
+
+//把数组里面的每个对象合并到一个对象里面
+let sidebar = sidebarlist.reduce((pre, cur) => Object.assign(pre, cur), {})
+Object.entries(sidebar).forEach(([key, items]) => {
+  let keyArr = splitPath(key)
+  let text = keyArr[keyArr.length - 1]
+  if(sidebarObj[`/${keyArr[0]}/`]){
+    sidebarObj[`/${keyArr[0]}/`].push({
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    })
+  }else{
+    sidebarObj[`/${keyArr[0]}/`] = [{
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    }]
+  }
+})
+
+const sidebarStr = JSON.stringify(sidebarObj, null, 2)
+//把sidebarStr写入到docs/.vitepress/sidebar/index.ts
+const sidebarPath = path.resolve(__dirname, '../docs/.vitepress/sidebar/index.ts')
+
+//没有则创建
+if (!fs.existsSync(sidebarPath)) {
+  fs.mkdirSync(path.resolve(__dirname, '../docs/.vitepress/sidebar'))
+}
+
+fs.writeFileSync(sidebarPath, `export default ${sidebarStr}`)
+
+//判断是否是文件夹
+function isArticleDir(dir) {
+  let exclude = ['public', 'index.md','vite.config.ts']  //排除的文件夹
+  return !exclude.includes(dir) && !dir.startsWith('.')
+}
+
+function splitPath(path) {
+  return path.split('/').filter((item) => item !== '')
+}
+function deepGetFile(dir) {
+  let backList = []
+  let list = fs.readdirSync(dir).filter((item) => isArticleDir(item))
+
+  for (let index in list) {
+    let item = path.resolve(dir, list[index])
+    if (fs.statSync(item).isDirectory()) {
+      backList = backList.concat(deepGetFile(item))
+    } else {
+      //输出相对路径
+      item = item.replace(path.resolve(__dirname, '../docs'), '').replace(/\\/g, '/')
+      backList.push(item)
+    }
+  }
+  return backList
+}
+
+// 生成侧边栏
+function deepGenerateSidebar(arr) {
+  //递归按照最后一级目录生成侧边栏
+  const sidebar = {}
+  sidebars.forEach((item) => {
+    const [dir, ...rest] = splitPath(item)
+    if (!sidebar[dir]) {
+      sidebar[dir] = []
+    }
+    sidebar[dir].push(item)
+  })
+  let sidebarList = []
+  //按最后一级目录分组
+  for (let key in sidebar) {
+    let pathPice = sidebar[key].map((item) => splitPath(item))
+    //如果pathPice[pathPice.length-1]相同,则合并
+    pathPice = pathPice.reduce((pre, cur) => {
+      let dirStr = cur.slice(0, -1).join('/') // /problem/vueproject/
+      let text = cur[cur.length - 1].replace(/\.md$/, '')
+      let link = '/' + cur.join('/').replace(/\.md$/, '')
+      pre[dirStr] = pre[dirStr] ? [...pre[dirStr], { text, link }] : [{ text, link }]
+      return pre
+    }, {})
+    sidebarList.push(pathPice)
+  }
+  return sidebarList
+}

VitePress添加本地搜索功能

WARNING

折腾了三遍Algolia都没能添加上搜索功能,最后在找到了这个issus里大佬提供的解决方案,成功添加上了本地搜索功能。

安装插件

bash
npm i vitepress-plugin-search markdown-it flexsearch -D
npm i vitepress-plugin-search markdown-it flexsearch -D

添加和配置插件

坑点

1.README 没写在哪个目录下存放vite.config.ts,依据经验放在根目录下不管用,放在.vitepress也不生效,最后挨个试才发现需要放在docs

2.示例没有引入flexSearchIndexOptions,需要手动从flexsearch中引入

3.引入后发现之前搜索框样式没了,需要在.vitepress/theme/styles/index.css下重新覆盖样式

image-20230205233032922

typescript

+//vite.config.ts
+import { SearchPlugin } from "vitepress-plugin-search";
+import { defineConfig } from "vite";
+import flexSearchIndexOptions   from "flexsearch";
+//default options
+var options = {
+  ...flexSearchIndexOptions,
+  previewLength: 100,//搜索结果预览长度
+  buttonLabel: "搜索",
+  placeholder: "情输入关键词",
+};
+
+export default defineConfig({
+  plugins: [SearchPlugin(options)],
+});

+//vite.config.ts
+import { SearchPlugin } from "vitepress-plugin-search";
+import { defineConfig } from "vite";
+import flexSearchIndexOptions   from "flexsearch";
+//default options
+var options = {
+  ...flexSearchIndexOptions,
+  previewLength: 100,//搜索结果预览长度
+  buttonLabel: "搜索",
+  placeholder: "情输入关键词",
+};
+
+export default defineConfig({
+  plugins: [SearchPlugin(options)],
+});

样式覆盖

css
.DocSearch-Button {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin: 0;
+  padding: 0;
+  width: 32px;
+  height: 32px;
+  border-radius: 4px;
+  background: transparent;
+  transition: border-color 0.25s;
+}
+@media (min-width: 768px) {
+  .DocSearch-Button {
+    justify-content: flex-start;
+    border: 1px solid transparent;
+    border-radius: 8px;
+    padding: 0 10px 0 12px;
+    width: 100%;
+    height: 40px;
+    background-color: var(--vp-c-bg-alt);
+  }
+}
+@media (max-width: 768px) {
+  .DocSearch-Button-Keys {
+    display: none;
+  }
+  .VPNavBarHamburger{
+    height: 32px !important;
+    width: 32px !important;
+    border-radius: 4px;
+  }
+}
.DocSearch-Button {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin: 0;
+  padding: 0;
+  width: 32px;
+  height: 32px;
+  border-radius: 4px;
+  background: transparent;
+  transition: border-color 0.25s;
+}
+@media (min-width: 768px) {
+  .DocSearch-Button {
+    justify-content: flex-start;
+    border: 1px solid transparent;
+    border-radius: 8px;
+    padding: 0 10px 0 12px;
+    width: 100%;
+    height: 40px;
+    background-color: var(--vp-c-bg-alt);
+  }
+}
+@media (max-width: 768px) {
+  .DocSearch-Button-Keys {
+    display: none;
+  }
+  .VPNavBarHamburger{
+    height: 32px !important;
+    width: 32px !important;
+    border-radius: 4px;
+  }
+}
+ + + + \ No newline at end of file diff --git "a/Problem/VitePress/VuePress\350\270\251\345\235\221\350\256\260\345\275\225.html" "b/Problem/VitePress/VuePress\350\270\251\345\235\221\350\256\260\345\275\225.html" new file mode 100644 index 00000000..5f8637c6 --- /dev/null +++ "b/Problem/VitePress/VuePress\350\270\251\345\235\221\350\256\260\345\275\225.html" @@ -0,0 +1,35 @@ + + + + + + VuePress踩坑记录 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

VuePress踩坑记录

坑点一、自定义目录不能根据视口固定

巨坑

找了好多博客参考,没发现有相关的问题,挠破头皮都没想明白啥原因,还好碰到一篇博客解决了疑惑

WARNING

产生原因:当一个元素position特性值设置为fixed时,如果该元素的先祖容器中存在transform特性值为非none的元素,则

position: fixed; 将相对于该先祖容器定位!!! 最后发现祖先元素有transform: translateY(0px);这行代码在作怪!!

解决方法:自定义样式覆盖就好啦

css
.page>section {
+    transform: none!important;
+}
.page>section {
+    transform: none!important;
+}

坑点二、引用的Gitee图床图片没显示

有人说是图床的问题、防盗链的问题,最后才发现自己把图床项目设为私有的项目了,重新设为开源成功解决

坑点三、Hexo博客源码没有备份,误点VsCode放弃所有更改并且回退版本

天坑

因学习配置博客用git action来自动化部署,配置完后发现打包报错,搞了好久没办法解决。 本来想执行git checkout .,看到VsCode有个快捷按钮,由于之前没有备份博客源码,点了一下直接回到解放前!

领悟

来到了新的阵地VuePress折腾,学到了码农必备技能------备份

+ + + + \ No newline at end of file diff --git "a/Problem/VueProject/Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.html" "b/Problem/VueProject/Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.html" new file mode 100644 index 00000000..bed0c96e --- /dev/null +++ "b/Problem/VueProject/Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.html" @@ -0,0 +1,435 @@ + + + + + + Vue项目踩坑一 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

Vue项目踩坑一

webpack-bundle-analyzer插件

安装后使用完把--report参数去掉,还是会给你生成打包文件,并会提示8888端口被占用,

需要在vue.config.js注释插件的使用,才能不被影响

点击弹窗父子传值成功,但是数据没有展示

恰巧性能优化,后端改动了大量的关联关系,刚开始以为后端改动数据层级嵌套太深vue丢失了响应式的原因,

最后才发现是前端element-ui全局引入改为按需引入, DescriptionsItem 组件漏写了(没有警告、报错提示,巨坑)

html
  <el-dialog
+  :title="title"
+  :visible="visible"
+   :before-close="close"  :close-on-click-modal="false">    
+   <el-descriptions   border>
+        <!--在main.js漏了导入并使用DescriptionsItem-->
+        <el-descriptions-item label="ID"> {{accountInfo.id}} </el-descriptions-item>
+        <el-descriptions-item label="name"> {{accountInfo.name}} </el-descriptions-item>
+    </el-descriptions>
+</el-dialog>
  <el-dialog
+  :title="title"
+  :visible="visible"
+   :before-close="close"  :close-on-click-modal="false">    
+   <el-descriptions   border>
+        <!--在main.js漏了导入并使用DescriptionsItem-->
+        <el-descriptions-item label="ID"> {{accountInfo.id}} </el-descriptions-item>
+        <el-descriptions-item label="name"> {{accountInfo.name}} </el-descriptions-item>
+    </el-descriptions>
+</el-dialog>

'确定'按钮点击失效问题

image-20230219214203987

vue
<template>
+	<div class="text-update-wrap">
+		<p class="text-show" v-if="!isEditing">
+			<span
+				class="single-overflow text-val"
+				:style="{ 'max-width': maxWidth }"
+        :title="text"
+				>{{ text }}</span
+			>
+			<span class="el-icon-edit" @click="switchToEdit"></span>
+		</p>
+		<p class="text-edit" v-else>
+			<el-input
+				v-model="inputVal"
+				ref="inputRef"
+				:placeholder="'请输入' + name"
+				size="mini"
+				clearable
+			></el-input>
+       <!-- @blur='cancelUpdate' 事件比confirmUpdate先执行,导致确定按钮事件没触发-->
+			<span
+				title="确定"
+				:class="loading ? 'el-icon-loading' : 'el-icon-circle-check'"
+				@click="confirmUpdate"
+			></span>
+			<span
+				title="取消"
+				class="el-icon-circle-close"
+				@click="cancelEdit"
+				v-if="!loading"
+			></span>
+		</p>
+	</div>
+</template>
+
+<script>
+export default {
+	name: "UpdateText",
+	props: {
+		textVal: {
+			type: String,
+			default: "",
+		},
+		name: {
+			type: String,
+			default: "名称",
+		},
+		maxWidth: {
+			type: String,
+			default: "200px",
+		},
+    id: {
+      type: String,
+      default: "",
+    },
+	},
+	data() {
+		return {
+			loading: false,
+			isEditing: false,
+			inputVal: "",
+			text: this.textVal,
+		}
+	},
+	computed: {},
+	watch: {},
+	components: {},
+	methods: {
+		//切换到输入框模式
+		switchToEdit() {
+			this.inputVal = this.textVal
+			this.isEditing = true
+			this.$nextTick(() => {
+				this.$refs.inputRef.focus()
+			})
+		},
+    cancelEdit(){
+				this.isEditing = false	
+    },
+		//确定更新
+	   confirmUpdate() {
+			let { inputVal, name ,id} = this
+      let value = inputVal.trim()
+			if (value === "") {
+				this.$message.error(`${name}不能为空`)
+				return
+			}else if(value === this.textVal){
+				this.isEditing = false
+				return
+			}
+			this.loading = true
+      if(id){
+        this.$emit("confirm", value, id)
+      }else{
+        this.$emit("confirm", value)
+      }
+		},
+		successUpdate() {
+      let { inputVal, name } = this
+			this.loading = false
+			this.text = inputVal
+			this.isEditing = false
+			this.$notify.success(`${name}修改成功`)
+		},
+    //失败
+    failUpdate() {
+      this.loading = false
+      this.$notify.error(`${this.name}修改失败`)
+    },
+	},
+	created() {},
+	mounted() {
+		//解决方案:不使用@blur, 监听焦点不在此组件时,才取消编辑
+		document.addEventListener("click", (e) => {
+			if (!this.$el.contains(e.target)) {
+				this.cancelEdit()
+			}
+		})
+	},
+}
+</script>
<template>
+	<div class="text-update-wrap">
+		<p class="text-show" v-if="!isEditing">
+			<span
+				class="single-overflow text-val"
+				:style="{ 'max-width': maxWidth }"
+        :title="text"
+				>{{ text }}</span
+			>
+			<span class="el-icon-edit" @click="switchToEdit"></span>
+		</p>
+		<p class="text-edit" v-else>
+			<el-input
+				v-model="inputVal"
+				ref="inputRef"
+				:placeholder="'请输入' + name"
+				size="mini"
+				clearable
+			></el-input>
+       <!-- @blur='cancelUpdate' 事件比confirmUpdate先执行,导致确定按钮事件没触发-->
+			<span
+				title="确定"
+				:class="loading ? 'el-icon-loading' : 'el-icon-circle-check'"
+				@click="confirmUpdate"
+			></span>
+			<span
+				title="取消"
+				class="el-icon-circle-close"
+				@click="cancelEdit"
+				v-if="!loading"
+			></span>
+		</p>
+	</div>
+</template>
+
+<script>
+export default {
+	name: "UpdateText",
+	props: {
+		textVal: {
+			type: String,
+			default: "",
+		},
+		name: {
+			type: String,
+			default: "名称",
+		},
+		maxWidth: {
+			type: String,
+			default: "200px",
+		},
+    id: {
+      type: String,
+      default: "",
+    },
+	},
+	data() {
+		return {
+			loading: false,
+			isEditing: false,
+			inputVal: "",
+			text: this.textVal,
+		}
+	},
+	computed: {},
+	watch: {},
+	components: {},
+	methods: {
+		//切换到输入框模式
+		switchToEdit() {
+			this.inputVal = this.textVal
+			this.isEditing = true
+			this.$nextTick(() => {
+				this.$refs.inputRef.focus()
+			})
+		},
+    cancelEdit(){
+				this.isEditing = false	
+    },
+		//确定更新
+	   confirmUpdate() {
+			let { inputVal, name ,id} = this
+      let value = inputVal.trim()
+			if (value === "") {
+				this.$message.error(`${name}不能为空`)
+				return
+			}else if(value === this.textVal){
+				this.isEditing = false
+				return
+			}
+			this.loading = true
+      if(id){
+        this.$emit("confirm", value, id)
+      }else{
+        this.$emit("confirm", value)
+      }
+		},
+		successUpdate() {
+      let { inputVal, name } = this
+			this.loading = false
+			this.text = inputVal
+			this.isEditing = false
+			this.$notify.success(`${name}修改成功`)
+		},
+    //失败
+    failUpdate() {
+      this.loading = false
+      this.$notify.error(`${this.name}修改失败`)
+    },
+	},
+	created() {},
+	mounted() {
+		//解决方案:不使用@blur, 监听焦点不在此组件时,才取消编辑
+		document.addEventListener("click", (e) => {
+			if (!this.$el.contains(e.target)) {
+				this.cancelEdit()
+			}
+		})
+	},
+}
+</script>

文本溢出隐藏处理后对不齐问题

image-20230219214258711

css
.el-checkbox {
+  width: 200px;
+  ::v-deep .el-checkbox__label {
+    width: 186px;
+    vertical-align: middle; //需要重新设置对齐线
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}
.el-checkbox {
+  width: 200px;
+  ::v-deep .el-checkbox__label {
+    width: 186px;
+    vertical-align: middle; //需要重新设置对齐线
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}

路由组件切换,事件总线意外多次触发

js
//A路由组件
+this.$bus.$emit("searchDone")
//A路由组件
+this.$bus.$emit("searchDone")
js
//B路由组件
+mounted(){
+		this.$bus.$off('searchDone') //在每次绑定事件前,先解绑该事件
+
+		this.$bus.$on('searchDone',this.handleCurrentChange)
+	},
//B路由组件
+mounted(){
+		this.$bus.$off('searchDone') //在每次绑定事件前,先解绑该事件
+
+		this.$bus.$on('searchDone',this.handleCurrentChange)
+	},

前端配合 Nginx 服务开启 gzip 页面加载不出来

js
//vue.config.js
+plugins: [
+	new CompressionWebpackPlugin({
+		exclude: /node_modules/,
+		test: /\.(js|css)$/,
+		threshold: 10240, // 超过10kb的文件就压缩
+		deleteOriginalAssets: true, // 不删除源文件
+		algorithm: "gzip",
+		minRatio: 0.8,
+	}),
+],
//vue.config.js
+plugins: [
+	new CompressionWebpackPlugin({
+		exclude: /node_modules/,
+		test: /\.(js|css)$/,
+		threshold: 10240, // 超过10kb的文件就压缩
+		deleteOriginalAssets: true, // 不删除源文件
+		algorithm: "gzip",
+		minRatio: 0.8,
+	}),
+],

2023-03-30-14-58-50

TailwindCSS动态绑定类不能随着渐变

vue

+<template>
+  <header  :class="headerBg"></header>
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+//通过判断滚动的距离,来决定header 背景色的变化
+
+let headerBg = ref("bg-zinc-900/[.00]");
+const handleScroll = () => {
+  const scrollHeight = document.documentElement.scrollTop;
+  if (scrollHeight < 100) {
+    let opacity = (scrollHeight / 100).toFixed(1).slice(1);
+    headerBg.value = `bg-zinc-900/[${opacity}]`
+  } else {
+    headerBg.value = `bg-zinc-900/[1]`
+  }
+};
+  window.addEventListener("scroll", handleScroll);
+</script>

+<template>
+  <header  :class="headerBg"></header>
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+//通过判断滚动的距离,来决定header 背景色的变化
+
+let headerBg = ref("bg-zinc-900/[.00]");
+const handleScroll = () => {
+  const scrollHeight = document.documentElement.scrollTop;
+  if (scrollHeight < 100) {
+    let opacity = (scrollHeight / 100).toFixed(1).slice(1);
+    headerBg.value = `bg-zinc-900/[${opacity}]`
+  } else {
+    headerBg.value = `bg-zinc-900/[1]`
+  }
+};
+  window.addEventListener("scroll", handleScroll);
+</script>

监听非 window resize 事件不生效问题

不会生效原因: div 元素默认不会触发 resize 事件。在 window 对象上,浏览器会自动跟踪窗口的大小变化并触发 resize 事件,但在其他元素上,您需要自己编写代码来检测大小变化。可以使用 MutationObserver 或者 ResizeObserver 来监听元素大小变化。以下是使用 ResizeObserver 的示例代码:

js
mounted() {
+  this.tagListRef = this.$refs.tagListRef;
+  this.tagBoxRef = this.$refs.tagBoxRef;
+  this.resizeHandler()
+  
+  // 创建 ResizeObserver 实例
+  this.tagListResizeObserver = new ResizeObserver(this.resizeHandler);
+  // 监听 tagListRef 元素的大小变化
+  this.tagListResizeObserver.observe(this.tagListRef);
+  
+  this.tagListRef.addEventListener('wheel', this.handleScroll);
+},
+beforeUnmount() {
+  // 在组件卸载前,停止 ResizeObserver 实例
+  this.tagListResizeObserver.disconnect();
+},
+methods: {
+  handleScroll(e) {
+    e.preventDefault();
+    this.tagListRef.scrollLeft += e.deltaY * 100;
+  },
+  scrollHandler(direction) {
+    this.tagListRef.scrollLeft += direction * this.tagListWidth;
+  },
+  resizeHandler(entries) {
+    // entries 是 ResizeObserver 的回调参数,包含被观察的元素的信息
+    this.tagListWidth = this.tagListRef.clientWidth
+    this.tagBoxWidth = this.tagBoxRef.clientWidth
+  } 
+}
mounted() {
+  this.tagListRef = this.$refs.tagListRef;
+  this.tagBoxRef = this.$refs.tagBoxRef;
+  this.resizeHandler()
+  
+  // 创建 ResizeObserver 实例
+  this.tagListResizeObserver = new ResizeObserver(this.resizeHandler);
+  // 监听 tagListRef 元素的大小变化
+  this.tagListResizeObserver.observe(this.tagListRef);
+  
+  this.tagListRef.addEventListener('wheel', this.handleScroll);
+},
+beforeUnmount() {
+  // 在组件卸载前,停止 ResizeObserver 实例
+  this.tagListResizeObserver.disconnect();
+},
+methods: {
+  handleScroll(e) {
+    e.preventDefault();
+    this.tagListRef.scrollLeft += e.deltaY * 100;
+  },
+  scrollHandler(direction) {
+    this.tagListRef.scrollLeft += direction * this.tagListWidth;
+  },
+  resizeHandler(entries) {
+    // entries 是 ResizeObserver 的回调参数,包含被观察的元素的信息
+    this.tagListWidth = this.tagListRef.clientWidth
+    this.tagBoxWidth = this.tagBoxRef.clientWidth
+  } 
+}
+ + + + \ No newline at end of file diff --git a/Problem/index.html b/Problem/index.html new file mode 100644 index 00000000..c223c108 --- /dev/null +++ b/Problem/index.html @@ -0,0 +1,31 @@ + + + + + + 编程踩坑积累与总结 | ZerDocs + + + + + + + + + + + + + + + + +
Skip to content

编程踩坑积累与总结

TIP

这里主要记录编程遇到的问题,已经解决方案,以便以后回顾或找到更优解!

+ + + + \ No newline at end of file diff --git "a/assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.js" "b/assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.js" new file mode 100644 index 00000000..b6ec4258 --- /dev/null +++ "b/assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.js" @@ -0,0 +1,455 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/MongoDB笔记.md","filePath":"BackEnd/NodeJS/MongoDB笔记.md"}'),p={name:"BackEnd/NodeJS/MongoDB笔记.md"},o=l(`

一、相关概念

MongoDB是文档型的NoSQL数据库

image-20220508194905648

image-20220507220553150

优点

  1. 高性能

  2. 高可用性

  3. 可扩展分片集群

应用场景:(数据量大、读写操作频繁、对事务要求不高)

二、数据库操作

查看所有数据库

sh
show databases
+show dbs
+#连接数据库后默认在test库
+use testdb01 	#切换数据库
show databases
+show dbs
+#连接数据库后默认在test库
+use testdb01 	#切换数据库

image-20220507215028603

创建/删除数据库

shell
use 数据库名 	# use testdb01
+db 	#查看所在数据库
+db.dropDatabase() 	#删除当前所在库
use 数据库名 	# use testdb01
+db 	#查看所在数据库
+db.dropDatabase() 	#删除当前所在库

三、集合相关操作

shell
show collections; 	# 查看数据库集合	show tables;
+db.createCollection('collectionName',[option]);	 #显式创建集合
+db.users.insert({'name':'李四'}); 	#隐式创建集合 往不存在的集合插入数据
+db.users.drop(); 	#删除集合
show collections; 	# 查看数据库集合	show tables;
+db.createCollection('collectionName',[option]);	 #显式创建集合
+db.users.insert({'name':'李四'}); 	#隐式创建集合 往不存在的集合插入数据
+db.users.drop(); 	#删除集合

四、文档相关操作

1.查询

shell
db.users.find() 	#查询所有 SELECT * from users  
+db.getCollection('users').find()	#查询所有
+db.getCollection('users').findOne()	#查询第一个
+db.getCollection('users').findOne({name:'zhang3'})		#查询符合条件的第一个
+
+db.users.find( { name: 1, age: 1 } ) 	#SELECT _id,name,age from users 
+db.users.find( {  name: 1, age: 1, _id: 0 } ) 	#去除id字段
+db.users.find( { name: 0, age: 0 } ) 	#去除特定字段
+db.users.find().pretty() 	#格式化查询(适用于长/复杂数据)
db.users.find() 	#查询所有 SELECT * from users  
+db.getCollection('users').find()	#查询所有
+db.getCollection('users').findOne()	#查询第一个
+db.getCollection('users').findOne({name:'zhang3'})		#查询符合条件的第一个
+
+db.users.find( { name: 1, age: 1 } ) 	#SELECT _id,name,age from users 
+db.users.find( {  name: 1, age: 1, _id: 0 } ) 	#去除id字段
+db.users.find( { name: 0, age: 0 } ) 	#去除特定字段
+db.users.find().pretty() 	#格式化查询(适用于长/复杂数据)
  • 等值查询
shell
db.users.find( { age:18} )
+#	WHERE age = 18
db.users.find( { age:18} )
+#	WHERE age = 18
  • AND条件
shell
db.users.find( { age: { $lt: 30 } ,sex:'',} )
+#	WHERE sex = "男" AND age < 30
+db.users.find( { age:24, age: { $lt: 30 } } )  #相同字段and查询中出现多次,以最后一个为查询条件
+#	WHERE age < 30
db.users.find( { age: { $lt: 30 } ,sex:'',} )
+#	WHERE sex = "男" AND age < 30
+db.users.find( { age:24, age: { $lt: 30 } } )  #相同字段and查询中出现多次,以最后一个为查询条件
+#	WHERE age < 30
  • OR条件
shell
db.users.find( { $or: [{sex:'男'}, { age: { $lt: 30 } } ] } )
+#	WHERE sex = "男" OR age < 30
db.users.find( { $or: [{sex:'男'}, { age: { $lt: 30 } } ] } )
+#	WHERE sex = "男" OR age < 30
  • 同时使用AND和OR条件
shell
db.users.find( {
+    { like:'美女'},
+     $or: [{sex:'男'}, { age: { $lt: 30 } },{ name: /^p/ } ] 
+} )
+#	WHERE like = "美女" AND (sex = "男" OR age < 30 OR name LIKE "%p%")
db.users.find( {
+    { like:'美女'},
+     $or: [{sex:'男'}, { age: { $lt: 30 } },{ name: /^p/ } ] 
+} )
+#	WHERE like = "美女" AND (sex = "男" OR age < 30 OR name LIKE "%p%")
  • 查询条件中使用查询操作符
shell
db.users.find( { age: { $in: [ "20", "22" ] } } )
db.users.find( { age: { $in: [ "20", "22" ] } } )
  • 模糊查询
shell
db.users.find( { name:/张/} ) #查询名字中含有'张'的所有
+# WHERE name LIKE "%张%
db.users.find( { name:/张/} ) #查询名字中含有'张'的所有
+# WHERE name LIKE "%张%
  • 数组中的查询
shell
db.users.find(likes:{$size:3})	#查询'喜好'数组大小为3
db.users.find(likes:{$size:3})	#查询'喜好'数组大小为3
  • 排序
shell
db.users.find().sort({age:-1}) # 1 升序 	-1 降序 (没有这个字段的数据排在前面)
db.users.find().sort({age:-1}) # 1 升序 	-1 降序 (没有这个字段的数据排在前面)
  • 分页
shell
db.users.find().skip(40).limit(30) # 跳过40条数据查30条数据 (起始0,则从40开始)
db.users.find().skip(40).limit(30) # 跳过40条数据查30条数据 (起始0,则从40开始)
  • 条数
shell
db.users.find().count()
db.users.find().count()
  • 去重
shell
db.users.find().distinct('字段')
db.users.find().distinct('字段')
  • 对比语法:

image-20220507231641824

2.插入

  • 单条文档
shell
db.users.insert({'name':'李四',age:18,sex:''});  # 提示已弃用
+db.getCollection('users').insert({'name':'李四',age:18,sex:''})
+db.users.insertOne({'name':'赵六'})
db.users.insert({'name':'李四',age:18,sex:''});  # 提示已弃用
+db.getCollection('users').insert({'name':'李四',age:18,sex:''})
+db.users.insertOne({'name':'赵六'})
  • 多条文档
shell
db.users.insert([{name:'缘一'},{name:'二楞'}])
+db.users.insertMany([{name:'缘一1'},{name:'二楞1'}])
+db.getCollection('users').insertMany([{name:'zhang3',age:19},{name:'zhang4',age:19}])
db.users.insert([{name:'缘一'},{name:'二楞'}])
+db.users.insertMany([{name:'缘一1'},{name:'二楞1'}])
+db.getCollection('users').insertMany([{name:'zhang3',age:19},{name:'zhang4',age:19}])
  • 脚本方式
shell
for(let i =0;i<5;i++){ 
+	db.users.insert({id:i,name:'zhang'+i})
+}
for(let i =0;i<5;i++){ 
+	db.users.insert({id:i,name:'zhang'+i})
+}

3.删除

shell
db.users.remove({}) 	#删除所有文档
+db.users.remove({_id:ObjectId("62767f841f41a9d7de748124")})	 #删除某一条
+db.users.remove({age:20})	 #删除满足条件的数据
+
+db.getCollection('users').deleteOne({name:'zhang3'})	 #删除某一条
+db.getCollection('users').deleteMany({age:18})	 #删除满足条件的数据
db.users.remove({}) 	#删除所有文档
+db.users.remove({_id:ObjectId("62767f841f41a9d7de748124")})	 #删除某一条
+db.users.remove({age:20})	 #删除满足条件的数据
+
+db.getCollection('users').deleteOne({name:'zhang3'})	 #删除某一条
+db.getCollection('users').deleteMany({age:18})	 #删除满足条件的数据

4.更新

语法 :

js
db.集合名称.update(
+	<query>,
+    <update>,
+    {
+        updert:<boolean>, 
+        multi:<boolean>,
+    	writeConcern:<document> //抛出异常的级别
+    }
+)
db.集合名称.update(
+	<query>,
+    <update>,
+    {
+        updert:<boolean>, 
+        multi:<boolean>,
+    	writeConcern:<document> //抛出异常的级别
+    }
+)
shell
db.users.update({_id:ObjectId('627686574f57a31b328b63ab')},{$set:{age:24,likes:['代码','吃饭']}})  #指定更新
+db.users.update({age:18},{$set:{age:24,likes:['动漫','美女']}})  #更新匹配到的第一条
+db.users.update(
+    {age:18},
+    {$set:{age:24,likes:['动漫','美女']}},
+    {multi:true} 	#更新多条
+    {upsert:true} 	#不存在则插入
+)  #更新匹配到的所有
+
+db.getCollection('users').update({age:18},{$set:{age:24,likes:['动漫','美女']}})	#更新匹配到的第一条
db.users.update({_id:ObjectId('627686574f57a31b328b63ab')},{$set:{age:24,likes:['代码','吃饭']}})  #指定更新
+db.users.update({age:18},{$set:{age:24,likes:['动漫','美女']}})  #更新匹配到的第一条
+db.users.update(
+    {age:18},
+    {$set:{age:24,likes:['动漫','美女']}},
+    {multi:true} 	#更新多条
+    {upsert:true} 	#不存在则插入
+)  #更新匹配到的所有
+
+db.getCollection('users').update({age:18},{$set:{age:24,likes:['动漫','美女']}})	#更新匹配到的第一条

五、Mongoose学习

1.插入

js
exports.register = async (req,res,next)=>{
+  try {
+     let user = new User(req.body.user)
+     await user.save() 
+     //转化为json才能移除密码
+     user = user.toJSON()
+     delete user.password
+     res.send({
+       msg:'注册成功!',
+       user
+     });
+  } catch (error) {
+    next(error)
+  }
+}
exports.register = async (req,res,next)=>{
+  try {
+     let user = new User(req.body.user)
+     await user.save() 
+     //转化为json才能移除密码
+     user = user.toJSON()
+     delete user.password
+     res.send({
+       msg:'注册成功!',
+       user
+     });
+  } catch (error) {
+    next(error)
+  }
+}

2.删除

js
exports.deleteArticle = async (req,res,next)=>{
+  try {
+    let id = mongoose.Types.ObjectId(req.body.id)
+    const result = await Article.findByIdAndRemove(id)
+    console.log('result: ', result);
+    res.succ({
+      msg:'文章删除成功!'
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
exports.deleteArticle = async (req,res,next)=>{
+  try {
+    let id = mongoose.Types.ObjectId(req.body.id)
+    const result = await Article.findByIdAndRemove(id)
+    console.log('result: ', result);
+    res.succ({
+      msg:'文章删除成功!'
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}

3.更新

js
exports.updateArticle =async (req,res,next)=>{
+  const article = req.body.article
+  try {
+    let {_id:id,title,desc,body,tagList} = req.body.article 
+    
+    let article  = await  Article.findByIdAndUpdate(id, { $set:req.body.article},  {new:true})
+      res.succ({
+        msg:'文章更新成功!',
+        article:article
+      })
+  } catch (error) {
+    res.errs(error)
+  }
+}
exports.updateArticle =async (req,res,next)=>{
+  const article = req.body.article
+  try {
+    let {_id:id,title,desc,body,tagList} = req.body.article 
+    
+    let article  = await  Article.findByIdAndUpdate(id, { $set:req.body.article},  {new:true})
+      res.succ({
+        msg:'文章更新成功!',
+        article:article
+      })
+  } catch (error) {
+    res.errs(error)
+  }
+}

4.查询

js
//获取一个文章
+
+exports.getArticleById = async (req,res,next)=>{
+  try {
+      //映射用户
+    const article = await Article.findById(req.params.articleId).populate('author')
+    if(!article){
+     return  res.errs('文章不存在!')
+    }
+    res.succ({
+      msg:'文章查询成功!',
+      article
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
//获取一个文章
+
+exports.getArticleById = async (req,res,next)=>{
+  try {
+      //映射用户
+    const article = await Article.findById(req.params.articleId).populate('author')
+    if(!article){
+     return  res.errs('文章不存在!')
+    }
+    res.succ({
+      msg:'文章查询成功!',
+      article
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
js
// 获取文章列表
+exports.getArticles = async (req,res,next)=>{
+  try {
+   const {limit=20,offset=0,tag ,author,favorited,sortBy}  = req.body.conditions  || {}
+    const filter = {}
+    if(tag){
+      filter.tagList = tag
+    }
+    //某个作者的文章
+    if(author){
+      const user = await User.findOne({username:author})
+        filter.author =user? user._id:null;
+    }
+    const articleList = await Article.find(filter).skip(Number.parseInt(offset))
+    .limit(Number.parseInt(limit)).sort({creeateAt:-1,...sortBy})
+
+    const articleCount = await Article.find(filter).skip(offset).limit(limit).count()
+    const totalCount = await Article.countDocuments()
+    if(!articleList){
+     return  res.errs('暂无文章!')
+    }
+    res.succ({
+      msg:'文章查询列表成功!',
+      articleList,
+      articleCount,
+      totalCount
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}
// 获取文章列表
+exports.getArticles = async (req,res,next)=>{
+  try {
+   const {limit=20,offset=0,tag ,author,favorited,sortBy}  = req.body.conditions  || {}
+    const filter = {}
+    if(tag){
+      filter.tagList = tag
+    }
+    //某个作者的文章
+    if(author){
+      const user = await User.findOne({username:author})
+        filter.author =user? user._id:null;
+    }
+    const articleList = await Article.find(filter).skip(Number.parseInt(offset))
+    .limit(Number.parseInt(limit)).sort({creeateAt:-1,...sortBy})
+
+    const articleCount = await Article.find(filter).skip(offset).limit(limit).count()
+    const totalCount = await Article.countDocuments()
+    if(!articleList){
+     return  res.errs('暂无文章!')
+    }
+    res.succ({
+      msg:'文章查询列表成功!',
+      articleList,
+      articleCount,
+      totalCount
+    })
+  } catch (error) {
+    res.errs(error)
+  }
+}

5.模型

📝model/index.js

js
const mongoose = require('mongoose');
+const { dbUri  } = require('../config/config.default')
+mongoose.connect(dbUri);
+
+const db = mongoose.connection;
+
+db.on('error', console.error.bind(console, 'MongDB数据库连接失败!'));
+
+db.once('open', function() {
+  console.log('MongDB数据库连接成功!');
+});
+const Cat = mongoose.model('Cat', { name: String });
+
+module.exports = {
+  User:mongoose.model('User',require('./user')),
+  Article:mongoose.model('Article',require('./article')),
+}
const mongoose = require('mongoose');
+const { dbUri  } = require('../config/config.default')
+mongoose.connect(dbUri);
+
+const db = mongoose.connection;
+
+db.on('error', console.error.bind(console, 'MongDB数据库连接失败!'));
+
+db.once('open', function() {
+  console.log('MongDB数据库连接成功!');
+});
+const Cat = mongoose.model('Cat', { name: String });
+
+module.exports = {
+  User:mongoose.model('User',require('./user')),
+  Article:mongoose.model('Article',require('./article')),
+}

📝model/base.js

js
//基础模型 
+module.exports =  {
+  createAt:{
+    type:Date,
+    default:Date.now
+  },
+  updtedAt:{
+    type:Date,
+    default:Date.now
+  }
+}
//基础模型 
+module.exports =  {
+  createAt:{
+    type:Date,
+    default:Date.now
+  },
+  updtedAt:{
+    type:Date,
+    default:Date.now
+  }
+}

📝model/user.js

js

+const mongoose =  require('mongoose')
+const baseSchema = require('./base')
+const md5 = require('../util/md5')
+//用户模型
+const userSchema = new mongoose.Schema({
+  ...baseSchema,
+  username:{
+    type:String,
+    required:true
+  },
+  password:{
+    type:String,
+    required:true,
+    set:value => md5(value),
+    select:false,
+  },
+  email:{
+    type:String,
+    required:true
+  },
+  bio:{
+    type:String,
+    default:null
+  },
+  image:{
+    type:String,
+    default:null
+  },
+  
+})
+module.exports = userSchema

+const mongoose =  require('mongoose')
+const baseSchema = require('./base')
+const md5 = require('../util/md5')
+//用户模型
+const userSchema = new mongoose.Schema({
+  ...baseSchema,
+  username:{
+    type:String,
+    required:true
+  },
+  password:{
+    type:String,
+    required:true,
+    set:value => md5(value),
+    select:false,
+  },
+  email:{
+    type:String,
+    required:true
+  },
+  bio:{
+    type:String,
+    default:null
+  },
+  image:{
+    type:String,
+    default:null
+  },
+  
+})
+module.exports = userSchema

📝model/article.js

js
 const mongoose =  require('mongoose')
+const Schema = mongoose.Schema
+const baseSchema = require('./base')
+//文章模型
+const articleSchema = new mongoose.Schema({
+  ...baseSchema,
+  title:{
+    type:String,
+    required:true
+  },
+  desc:{
+    type:String,
+    required:true
+  },
+  body:{
+    type:String,
+    required:true
+  },
+  favoritesCount:{
+    type:Number,
+    default:0
+  },
+  tagList:{
+    type:[String],
+    default:null
+  },
+   author:{
+     type:Schema.Types.ObjectId,
+     ref:'User',
+     required:true,
+   }
+})
+module.exports = articleSchema
 const mongoose =  require('mongoose')
+const Schema = mongoose.Schema
+const baseSchema = require('./base')
+//文章模型
+const articleSchema = new mongoose.Schema({
+  ...baseSchema,
+  title:{
+    type:String,
+    required:true
+  },
+  desc:{
+    type:String,
+    required:true
+  },
+  body:{
+    type:String,
+    required:true
+  },
+  favoritesCount:{
+    type:Number,
+    default:0
+  },
+  tagList:{
+    type:[String],
+    default:null
+  },
+   author:{
+     type:Schema.Types.ObjectId,
+     ref:'User',
+     required:true,
+   }
+})
+module.exports = articleSchema
`,74),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.lean.js" "b/assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.lean.js" new file mode 100644 index 00000000..f0214726 --- /dev/null +++ "b/assets/BackEnd_NodeJS_MongoDB\347\254\224\350\256\260.md.eb6021c2.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/MongoDB笔记.md","filePath":"BackEnd/NodeJS/MongoDB笔记.md"}'),p={name:"BackEnd/NodeJS/MongoDB笔记.md"},o=l("",74),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.js" "b/assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.js" new file mode 100644 index 00000000..0a2a14e1 --- /dev/null +++ "b/assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.js" @@ -0,0 +1,247 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"Node大文件上传","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/Node大文件上传.md","filePath":"BackEnd/NodeJS/Node大文件上传.md"}'),p={name:"BackEnd/NodeJS/Node大文件上传.md"},o=l(`

Node大文件上传

  1. 创建文件唯一 HASH
  2. 发请求检查文件是否已传过
    1. 传过:提示'秒传成功'
    2. 未传过:开始切片并上传,创建任务池,循环上传切片
    3. 传过未传完:从下一切片开始传
  3. 上传完成,发送合并切片请求

Vue 前端代码

vue
<template>
+  <el-upload :http-request="customRequest">
+    <template #trigger>
+      <el-button type="primary">选择文件</el-button>
+    </template>
+  </el-upload>
+</template>
+<script lang="ts" setup>
+import axios from 'axios';
+import SparkMD5 from 'spark-md5'
+const customRequest = async ({ file }) => {
+  const formData = new FormData()
+  formData.append('fileName', file)
+  const hash = await calcFileHash(file)
+  const chunks = createFileChunk(file, hash)
+  // 检查文件是否存在
+  // const { data: { data: { exist } } } = await checkFileExist(hash)
+  const res = await uploadChunks(chunks, hash)
+}
+const checkFileExist = (hash) => {
+  return axios.post('http://localhost:3000/upload/checkFile', {
+    hash
+  })
+}
+type Chunk = {
+  name: string
+  index: number
+  chunk: Blob
+  hash: string
+}
+const ChunkSize = 1024 * 1024 * 2 // 2M
+// 创建分片
+const createFileChunk = (file, hash) => {
+  const chunks: Chunk[] = []
+  const chunkCount = Math.ceil(file.size / ChunkSize)
+  for (let i = 0; i < chunkCount; i++) {
+    const chunk: Blob = file.slice(i * ChunkSize, (i + 1) * ChunkSize)
+    const name = hash + "-" + i + "." + file.name.substring(file.name.lastIndexOf(".") + 1)
+    chunks.push({
+      name,
+      index: i,
+      chunk,
+      hash,
+    })
+  }
+  return chunks
+}
+// 创建文件hash值
+const calcFileHash = (file: File) => {
+  return new Promise(resolve => {
+    const spark = new SparkMD5.ArrayBuffer()
+    const reader = new FileReader()
+    const size = file.size
+    const offset = 2 * 1024 * 1024
+    // 第一个2M,最后一个区块数据全要
+    const chunks = [file.slice(0, offset)]
+    let cur = offset
+    while (cur < size) {
+      if (cur + offset >= size) {
+        // 最后一个区快
+        chunks.push(file.slice(cur, cur + offset))
+      } else {
+        // 中间的区块
+        const mid = cur + offset / 2
+        const end = cur + offset
+        chunks.push(file.slice(cur, cur + 2))
+        chunks.push(file.slice(mid, mid + 2))
+        chunks.push(file.slice(end - 2, end))
+      }
+      cur += offset
+    }
+    // 中间的,取前中后各2各字节
+    reader.readAsArrayBuffer(new Blob(chunks))
+    reader.onload = e => {
+      spark.append(e?.target?.result as ArrayBuffer)
+      resolve(spark.end())
+    }
+  })
+}
+// 上传分片
+const uploadChunks = async (chunks: Array<Chunk>, hash: string) => {
+  // 转成promise
+  const requestList = chunks.map(({ chunk, name, index, hash }) => {
+    const form = new FormData()
+    form.append('chunk', chunk, name)
+    form.append('hash', hash)
+    form.append('name', name)
+    return { form, index: index, error: 0 }
+  })
+
+  let index = 0
+  const taskPool: Array<Promise<any>> = []
+  const max = 6 // 设置浏览器运行最大并发数  目前6个为当前的主流
+  let allProgress = index // 总进度
+  while (index < requestList.length) {
+    const task = axios.post("http://localhost:3000/upload/postFile", requestList[index].form, {
+      onUploadProgress: (progress) => {
+        allProgress += (progress.loaded / (progress.total ? progress.total : 1)) // 这是单个分片的
+        const percent = ((allProgress / requestList.length) * 100)
+        // if (params.onProgress) params.onProgress({ percent })
+      }
+    })
+    task.then(() => {
+      taskPool.splice(taskPool.findIndex(item => item === task))
+    })
+    taskPool.push(task)
+    if (taskPool.length === max) {
+      await Promise.race(taskPool) // 竞赛等出一个执行完毕的请求
+    }
+    index++
+  }
+  console.log('[ taskPool ]-95', taskPool)
+
+  await Promise.all(taskPool)
+}
+
+
+</script>
+
+<style scoped lang="scss">
+.upload-demo {
+  margin: 100px 100px;
+}
+</style>
<template>
+  <el-upload :http-request="customRequest">
+    <template #trigger>
+      <el-button type="primary">选择文件</el-button>
+    </template>
+  </el-upload>
+</template>
+<script lang="ts" setup>
+import axios from 'axios';
+import SparkMD5 from 'spark-md5'
+const customRequest = async ({ file }) => {
+  const formData = new FormData()
+  formData.append('fileName', file)
+  const hash = await calcFileHash(file)
+  const chunks = createFileChunk(file, hash)
+  // 检查文件是否存在
+  // const { data: { data: { exist } } } = await checkFileExist(hash)
+  const res = await uploadChunks(chunks, hash)
+}
+const checkFileExist = (hash) => {
+  return axios.post('http://localhost:3000/upload/checkFile', {
+    hash
+  })
+}
+type Chunk = {
+  name: string
+  index: number
+  chunk: Blob
+  hash: string
+}
+const ChunkSize = 1024 * 1024 * 2 // 2M
+// 创建分片
+const createFileChunk = (file, hash) => {
+  const chunks: Chunk[] = []
+  const chunkCount = Math.ceil(file.size / ChunkSize)
+  for (let i = 0; i < chunkCount; i++) {
+    const chunk: Blob = file.slice(i * ChunkSize, (i + 1) * ChunkSize)
+    const name = hash + "-" + i + "." + file.name.substring(file.name.lastIndexOf(".") + 1)
+    chunks.push({
+      name,
+      index: i,
+      chunk,
+      hash,
+    })
+  }
+  return chunks
+}
+// 创建文件hash值
+const calcFileHash = (file: File) => {
+  return new Promise(resolve => {
+    const spark = new SparkMD5.ArrayBuffer()
+    const reader = new FileReader()
+    const size = file.size
+    const offset = 2 * 1024 * 1024
+    // 第一个2M,最后一个区块数据全要
+    const chunks = [file.slice(0, offset)]
+    let cur = offset
+    while (cur < size) {
+      if (cur + offset >= size) {
+        // 最后一个区快
+        chunks.push(file.slice(cur, cur + offset))
+      } else {
+        // 中间的区块
+        const mid = cur + offset / 2
+        const end = cur + offset
+        chunks.push(file.slice(cur, cur + 2))
+        chunks.push(file.slice(mid, mid + 2))
+        chunks.push(file.slice(end - 2, end))
+      }
+      cur += offset
+    }
+    // 中间的,取前中后各2各字节
+    reader.readAsArrayBuffer(new Blob(chunks))
+    reader.onload = e => {
+      spark.append(e?.target?.result as ArrayBuffer)
+      resolve(spark.end())
+    }
+  })
+}
+// 上传分片
+const uploadChunks = async (chunks: Array<Chunk>, hash: string) => {
+  // 转成promise
+  const requestList = chunks.map(({ chunk, name, index, hash }) => {
+    const form = new FormData()
+    form.append('chunk', chunk, name)
+    form.append('hash', hash)
+    form.append('name', name)
+    return { form, index: index, error: 0 }
+  })
+
+  let index = 0
+  const taskPool: Array<Promise<any>> = []
+  const max = 6 // 设置浏览器运行最大并发数  目前6个为当前的主流
+  let allProgress = index // 总进度
+  while (index < requestList.length) {
+    const task = axios.post("http://localhost:3000/upload/postFile", requestList[index].form, {
+      onUploadProgress: (progress) => {
+        allProgress += (progress.loaded / (progress.total ? progress.total : 1)) // 这是单个分片的
+        const percent = ((allProgress / requestList.length) * 100)
+        // if (params.onProgress) params.onProgress({ percent })
+      }
+    })
+    task.then(() => {
+      taskPool.splice(taskPool.findIndex(item => item === task))
+    })
+    taskPool.push(task)
+    if (taskPool.length === max) {
+      await Promise.race(taskPool) // 竞赛等出一个执行完毕的请求
+    }
+    index++
+  }
+  console.log('[ taskPool ]-95', taskPool)
+
+  await Promise.all(taskPool)
+}
+
+
+</script>
+
+<style scoped lang="scss">
+.upload-demo {
+  margin: 100px 100px;
+}
+</style>
`,4),e=[o];function c(t,r,y,B,A,D){return n(),a("div",null,e)}const u=s(p,[["render",c]]);export{C as __pageData,u as default}; diff --git "a/assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.lean.js" "b/assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.lean.js" new file mode 100644 index 00000000..38e33443 --- /dev/null +++ "b/assets/BackEnd_NodeJS_Node\345\244\247\346\226\207\344\273\266\344\270\212\344\274\240.md.84c9f765.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"Node大文件上传","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/Node大文件上传.md","filePath":"BackEnd/NodeJS/Node大文件上传.md"}'),p={name:"BackEnd/NodeJS/Node大文件上传.md"},o=l("",4),e=[o];function c(t,r,y,B,A,D){return n(),a("div",null,e)}const u=s(p,[["render",c]]);export{C as __pageData,u as default}; diff --git "a/assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.js" "b/assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.js" new file mode 100644 index 00000000..249e3ba2 --- /dev/null +++ "b/assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.js" @@ -0,0 +1,973 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/Node学习笔记.md","filePath":"BackEnd/NodeJS/Node学习笔记.md"}'),p={name:"BackEnd/NodeJS/Node学习笔记.md"},o=l(`

一、读取文件

js
const fs = require('fs')
+fs.readFile('1.txt','utf8',function(err,data){
+
+    console.log('data: ', data);//失败为undefined
+    console.log('err: ', err);//成功为null,否则为错误对象
+
+    if(err){
+	 return console.log('读取失败'+err.message)
+   }
+ console.log('读取成功'+data)
+})
const fs = require('fs')
+fs.readFile('1.txt','utf8',function(err,data){
+
+    console.log('data: ', data);//失败为undefined
+    console.log('err: ', err);//成功为null,否则为错误对象
+
+    if(err){
+	 return console.log('读取失败'+err.message)
+   }
+ console.log('读取成功'+data)
+})

问题

  • 相对路径在上一层读取不了文件
  • 绝对路径不利于维护移植

解决

__dirname代表当前文件所处目录, 解决文件路径动态拼接问题

坑点__dirname输出是路径是**反斜杠(\\),拼接后面的路径需要写正斜杠(/)**

js
//__dirname:  D:\\PracticeProject\\Node\\readfile
+
+fs.readFile(__dirname+'/3.txt','utf8',function(err,data){
+    __dirname+'\\\\\\\\3.txt',
+    __dirname+'\\\\\\3.txt',
+     __dirname+'\\\\\\3.txt',
+    __dirname+'/\\\\3.txt',
+   console.log('__dirname: ', __dirname+'\\\\3.txt');//这四个都可以成功(?)
+
+  console.log('__dirname: ', __dirname);
+    console.log('data: ', data);
+    if(err){
+	    return console.log('读取失败'+err.message)
+   }
+})
//__dirname:  D:\\PracticeProject\\Node\\readfile
+
+fs.readFile(__dirname+'/3.txt','utf8',function(err,data){
+    __dirname+'\\\\\\\\3.txt',
+    __dirname+'\\\\\\3.txt',
+     __dirname+'\\\\\\3.txt',
+    __dirname+'/\\\\3.txt',
+   console.log('__dirname: ', __dirname+'\\\\3.txt');//这四个都可以成功(?)
+
+  console.log('__dirname: ', __dirname);
+    console.log('data: ', data);
+    if(err){
+	    return console.log('读取失败'+err.message)
+   }
+})

path 路径模块

js
const pathStr = path.join('/a','/b/c','../','/d')  //  a\\b\\d 抵消路劲(../)
const pathStr = path.join('/a','/b/c','../','/d')  //  a\\b\\d 抵消路劲(../)

获取文件扩展名

js
const fext = path.extname(fpath)
const fext = path.extname(fpath)

二、写入文件

js
const fs = require('fs')
+fs.writeFile('F:/12.txt','888888',function(err  ){
+
+  if(err){
+    console.log('写入失败 ', err.message);
+  }
+  //写入成功,错误为null
+     console.log('写入成功');
+})
const fs = require('fs')
+fs.writeFile('F:/12.txt','888888',function(err  ){
+
+  if(err){
+    console.log('写入失败 ', err.message);
+  }
+  //写入成功,错误为null
+     console.log('写入成功');
+})

fs.writeFile 只能创建文件,不能创建路径

重复调用 fs.writeFile 写入同一个文件,新写入的会覆盖之前内容

三、服务器操作

服务器与普通电脑:服务器上安装了 web 服务器软件

1.创建 web 服务器步骤

  • 导入 http 模块
  • 创建 web 服务器实例
  • 为服务器实例绑定 request 事件,监听客户端请求
  • 启动服务器
js
const http = require('http')
+const server = http.createServer()
+server.on('request',(req,res)=>{
+    //返回数据给客户端(解决中文乱码两种方法)
+     res.writeHead(200, { "Content-Type": "text/plain;charset=utf-8" });
+    // res.setHeader('Content-Type','text/html; charset=utf-8')
+ 	 res.end('请求url:'+req.url+',请求方法:'+req.method)
+	 console.log('服务器监听到请求')
+})
+server.listen(80,()=>{
+	console.log('服务器运行在 127.0.0.1')
+})
const http = require('http')
+const server = http.createServer()
+server.on('request',(req,res)=>{
+    //返回数据给客户端(解决中文乱码两种方法)
+     res.writeHead(200, { "Content-Type": "text/plain;charset=utf-8" });
+    // res.setHeader('Content-Type','text/html; charset=utf-8')
+ 	 res.end('请求url:'+req.url+',请求方法:'+req.method)
+	 console.log('服务器监听到请求')
+})
+server.listen(80,()=>{
+	console.log('服务器运行在 127.0.0.1')
+})

2.动态响应内容

js
const http = require("http");
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  const url = req.url;
+  let content = \`<h1>Not Found 404</h1>\`;
+  if (url === "/" || url === "/index.html") {
+    content = \`<h1>Home</h1>\`;
+  } else if (url === "/about.html") {
+    content = \`<h1>About</h1>\`;
+  }
+  res.setHeader('Content-Type','text/html; charset=utf-8')
+  res.end(content);
+});
+server.listen(80, () => {
+  console.log("运行在localhost:8080");
+});
const http = require("http");
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  const url = req.url;
+  let content = \`<h1>Not Found 404</h1>\`;
+  if (url === "/" || url === "/index.html") {
+    content = \`<h1>Home</h1>\`;
+  } else if (url === "/about.html") {
+    content = \`<h1>About</h1>\`;
+  }
+  res.setHeader('Content-Type','text/html; charset=utf-8')
+  res.end(content);
+});
+server.listen(80, () => {
+  console.log("运行在localhost:8080");
+});

3.响应文件内容

js
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const fpath = req.url;
+    //映射服务器文件路径
+  fs.readFile(path.join(__dirname, fpath), "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const fpath = req.url;
+    //映射服务器文件路径
+  fs.readFile(path.join(__dirname, fpath), "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});

优化访问方式

js
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const url = req.url
+  let fpath = '';
+
+    //让访问(/,/index.html,/stock-roolup/index.html)都可以得到响应
+  if(url ==='/'){
+    fpath = path.join(__dirname,'/stock-rollup/index.html')
+  }else if(url === '/index.html'){
+    fpath = path.join(__dirname,'/stock-rollup',url)
+  }else if(url === '/stock-rollup/index.html'){
+    fpath = path.join(__dirname, url)
+  }
+  console.log('fpath: ', fpath);
+  fs.readFile(fpath, "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});
const http = require("http");
+const path = require("path");
+const fs = require("fs");
+
+const server = http.createServer();
+
+server.on("request", (req, res) => {
+  console.log("请求路径和方式 ", req.url, req.method);
+  const url = req.url
+  let fpath = '';
+
+    //让访问(/,/index.html,/stock-roolup/index.html)都可以得到响应
+  if(url ==='/'){
+    fpath = path.join(__dirname,'/stock-rollup/index.html')
+  }else if(url === '/index.html'){
+    fpath = path.join(__dirname,'/stock-rollup',url)
+  }else if(url === '/stock-rollup/index.html'){
+    fpath = path.join(__dirname, url)
+  }
+  console.log('fpath: ', fpath);
+  fs.readFile(fpath, "utf-8", (err, data) => {
+    if (err) {
+      res.end("<h1>Not Found 404</h1>");
+      return console.log("读取失败");
+    }
+    res.setHeader("Content-Type", "text/html; charset=utf-8");
+    res.end(data);
+  });
+});
+
+server.listen(8888, () => {
+  console.log("服务器运行在localhost:8888");
+});

四、Node 模块化

模块分为:内置模块、自定义模块、第三方模块

1.module 对象

在自定义模块中,module.exports模式是空对象,使用module.exports将模块内部成员共享

image-20220430114048249

2.模块共享

m1.js

js
const name = 'zhangsan'
+
+module.exports.name ='lisi'
+console.log('module-m1: ', module);
const name = 'zhangsan'
+
+module.exports.name ='lisi'
+console.log('module-m1: ', module);

m2.js

js
const m1 = require('./m1')
+console.log(m1.name);
const m1 = require('./m1')
+console.log(m1.name);

运行: node m2.js

image-20220430120846611

导出的对象以module.expports为准, 使用require()得到的永远是module.expports指向的对象

js
//m1.js
+exports.name = 'zhangsan'
+exports.age = 18
+
+module.exports={
+  name:'lisi',
+  age:20
+}
+//m2.js
+const m1 = require('./m1')
+console.log(m1.name); //lisi
+console.log(m1.age); //20
//m1.js
+exports.name = 'zhangsan'
+exports.age = 18
+
+module.exports={
+  name:'lisi',
+  age:20
+}
+//m2.js
+const m1 = require('./m1')
+console.log(m1.name); //lisi
+console.log(m1.age); //20

image-20220430121633293

五、模块加载机制

  1. 优先从缓存中加载,模块多次 require()只会执行一次

  2. 内置模块的加载优先级是最高的

  3. 自定义模块 require 时,必须在路径指定./或../开头的路径标识符

image-202205022209230724. 第三方模块记载机制

image-20220502221028461

  1. 目录作为模块

    image-20220502221133208

六、Express 模块

前端两种服务器:

​ Web 网站服务器:专门对外提供 Web 网页资源服务器

​ API 接口服务器:专门对外提供 API 接口服务器

1.Express 创建服务器

js
const express = require('express')
+const app = express()
+
+app.get('/zhj',(req,res)=>{
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
const express = require('express')
+const app = express()
+
+app.get('/zhj',(req,res)=>{
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})

2.Express 中间件

  • 概念

image-20220501095630708

  • 定义与使用全局中间件

    可以调用多个中间件对请求进行**预处理**

    image-20220501095912439

js
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+app.use(mw)
+app.get('/zjj',(req,res)=>{
+  console.log('req.name: ', req.name); //zhangsan
+  console.log('zjj被访问');
+  res.send('zjj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+app.use(mw)
+app.get('/zjj',(req,res)=>{
+  console.log('req.name: ', req.name); //zhangsan
+  console.log('zjj被访问');
+  res.send('zjj被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
  • 中间件本质

    next 函数可以流转关系转交给下一个中间件或路由

image-20220501100043506

  • 局部中间件
js

+...
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+//在路由加一个参数,
+app.get('/mw1',mw1,(req,res)=>{
+  console.log('req.age: ', req.age);
+  console.log('mw1被访问');
+  res.send('mw1被访问哈哈哈')
+})
+...

+...
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+//在路由加一个参数,
+app.get('/mw1',mw1,(req,res)=>{
+  console.log('req.age: ', req.age);
+  console.log('mw1被访问');
+  res.send('mw1被访问哈哈哈')
+})
+...
  • 多个局部中间件
js
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+const mw2 = (req,res,next) => {
+  console.log('中间件mw2被执行了');
+  req.age= 20
+  next()
+}
+app.use(mw)
+app.get('/zhj',(req,res)=>{
+  console.log('req.name: ', req.name);
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+//两种传参方式
+app.get('/mw1',[mw1,mw2],(req,res)=>{
+//app.get('/mw1',mw1,mw2,(req,res)=>{
+  console.log('req.age: ', req.age); //20
+  res.send('mw1被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})
const express = require('express')
+const app = express()
+
+const mw = (req,res,next) => {
+  console.log('全局中间件被执行了');
+  req.name= 'zhangsan'
+  next()
+}
+const mw1 = (req,res,next) => {
+  console.log('中间件mw1被执行了');
+  req.age= 18
+  next()
+}
+const mw2 = (req,res,next) => {
+  console.log('中间件mw2被执行了');
+  req.age= 20
+  next()
+}
+app.use(mw)
+app.get('/zhj',(req,res)=>{
+  console.log('req.name: ', req.name);
+  console.log('zhj被访问');
+  res.send('zhj被访问哈哈哈')
+})
+//两种传参方式
+app.get('/mw1',[mw1,mw2],(req,res)=>{
+//app.get('/mw1',mw1,mw2,(req,res)=>{
+  console.log('req.age: ', req.age); //20
+  res.send('mw1被访问哈哈哈')
+})
+app.listen(80,()=>{
+  console.log('run 80');
+})

image-20220501101526777

  • 中间件注意事项
  1. 一定要在路由之前注册中间件
  2. 可以连续调用多个中间件对请求进行处理
  3. 中间件函数必须有next()函数
  4. next()后不要写额外代码
  5. 连续调用的多个中间件共享 req 和 res 对象
  • 中间件分类
  1. 应用级别中间件:绑定到 app 实例上的中间件
  2. 路由级别中间件:绑定到 router 实例上的中间件
  3. 错误级别中间件:捕获项目异常错误的中间件

七、编写接口

js
//index.js
+const express = require('express')
+const router = require('./router')
+
+const app = express()
+
+//配置解析urlencoded请求体中间件(在路由中间件前使用)
+app.use(express.urlencoded({extended:false}))
+
+//CORS解决跨域
+const cors = require('cors')
+app.use(cors)
+
+app.use('/api',router)
+
+app.listen(80,()=>{
+  console.log('server running 127.0.0.1:80');
+})
//index.js
+const express = require('express')
+const router = require('./router')
+
+const app = express()
+
+//配置解析urlencoded请求体中间件(在路由中间件前使用)
+app.use(express.urlencoded({extended:false}))
+
+//CORS解决跨域
+const cors = require('cors')
+app.use(cors)
+
+app.use('/api',router)
+
+app.listen(80,()=>{
+  console.log('server running 127.0.0.1:80');
+})
js
//router.js
+const express = require('express')
+const apiRouter = express.Router()
+
+apiRouter.get('/get',(req,res)=>{
+  console.log('req.query: ', req.query);
+  res.send({
+    status:200,
+    message:'GET 请求成功',
+    success:1,
+    data:{
+      name:'zhangsan',
+      age:18
+    }
+  })
+})
+apiRouter.post('/post',(req,res)=>{
+  console.log('req.body',req.body);
+  res.send({
+    status:200,
+    message:'POST 请求成功',
+    success:1,
+    data:req.body
+  })
+})
+
+module.exports = apiRouter
//router.js
+const express = require('express')
+const apiRouter = express.Router()
+
+apiRouter.get('/get',(req,res)=>{
+  console.log('req.query: ', req.query);
+  res.send({
+    status:200,
+    message:'GET 请求成功',
+    success:1,
+    data:{
+      name:'zhangsan',
+      age:18
+    }
+  })
+})
+apiRouter.post('/post',(req,res)=>{
+  console.log('req.body',req.body);
+  res.send({
+    status:200,
+    message:'POST 请求成功',
+    success:1,
+    data:req.body
+  })
+})
+
+module.exports = apiRouter

1. CORS 跨域资源共享

image-20220502115641176

2.CORS 头部

image-20220502120846061

image-20220502120941415

image-20220502121028306

image-20220502121159109

image-20220502120738921

八、Node 连接数据库

1.配置 mysql 模块

  • 安装 mysql 模块:\`npm i mysql

  • 连接数据库并测试 mysql 是否连接成功

js
const mysql = require('mysql')
+
+const db = mysql.createPool({
+  host:'127.0.0.1',
+  user:'root',
+  password:'root',
+  database:'mydb01'
+})
+
+//测试
+db.query('select 1',(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res); //res:  [ RowDataPacket { '1': 1 } ]
+})
const mysql = require('mysql')
+
+const db = mysql.createPool({
+  host:'127.0.0.1',
+  user:'root',
+  password:'root',
+  database:'mydb01'
+})
+
+//测试
+db.query('select 1',(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res); //res:  [ RowDataPacket { '1': 1 } ]
+})

2.查询数据

js
//查询语句
+const qstr = 'select * from users'
+db.query(qstr ,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res);
+})
+/*查询结果:
+res:  [
+  RowDataPacket { id: 1, name: '张三', age: 19 },
+  RowDataPacket { id: 2, name: '李四', age: 22 }
+]
+*/
//查询语句
+const qstr = 'select * from users'
+db.query(qstr ,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res: ', res);
+})
+/*查询结果:
+res:  [
+  RowDataPacket { id: 1, name: '张三', age: 19 },
+  RowDataPacket { id: 2, name: '李四', age: 22 }
+]
+*/

3.插入数据

js
//方式一:
+let zl = {
+  id:6,
+  name:'zhaoliu',
+  age:21
+}
+//占位符的数量和表的列数需要一致,
+//否则报错ER_WRONG_VALUE_COUNT_ON_ROW: Column count doesn't match value count at row 1
+const istr = \`insert into users values(?,?,?)\`
+db.query(istr,[zl.id,zl.name,zl.age],(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res:',res);//res.affectedRows大于0表示插入成功
+})
+/* 返回结果:
+res: OkPacket {
+  fieldCount: 0,
+  affectedRows: 1,
+  insertId: 3,
+  serverStatus: 2,
+  warningCount: 0,
+  message: '',
+  protocol41: true,
+  changedRows: 0
+}
+*/
+
+//方式二:(便捷形式)
+const istr = \`insert into users set ?\`
+db.query(istr,zl,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+ if(res.affectedRows>0){
+     console.log('插入成功',);
+ }
+})
//方式一:
+let zl = {
+  id:6,
+  name:'zhaoliu',
+  age:21
+}
+//占位符的数量和表的列数需要一致,
+//否则报错ER_WRONG_VALUE_COUNT_ON_ROW: Column count doesn't match value count at row 1
+const istr = \`insert into users values(?,?,?)\`
+db.query(istr,[zl.id,zl.name,zl.age],(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+  console.log('res:',res);//res.affectedRows大于0表示插入成功
+})
+/* 返回结果:
+res: OkPacket {
+  fieldCount: 0,
+  affectedRows: 1,
+  insertId: 3,
+  serverStatus: 2,
+  warningCount: 0,
+  message: '',
+  protocol41: true,
+  changedRows: 0
+}
+*/
+
+//方式二:(便捷形式)
+const istr = \`insert into users set ?\`
+db.query(istr,zl,(err,res)=>{
+  if(err){
+    return console.log(err.message);
+  }
+ if(res.affectedRows>0){
+     console.log('插入成功',);
+ }
+})

4.更新数据

js
//方式一:
+let user = {
+  id: 6,
+  name: "laoqi",
+  age: 30,
+};
+const ustr = \`update  users set name=?,age=? where id=?\`;
+db.query(ustr, [user.name, user.age, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  console.log("res: ", res);
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});
+//方式二:(便捷形式)
+const ustr = \`update  users set ? where id=?\`;
+db.query(ustr, [user, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});
//方式一:
+let user = {
+  id: 6,
+  name: "laoqi",
+  age: 30,
+};
+const ustr = \`update  users set name=?,age=? where id=?\`;
+db.query(ustr, [user.name, user.age, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  console.log("res: ", res);
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});
+//方式二:(便捷形式)
+const ustr = \`update  users set ? where id=?\`;
+db.query(ustr, [user, user.id], (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("更新成功");
+  }
+});

5.删除数据

  • 硬删除
js
let dstr = "delete from users where id=?";
+//只有一个占位符可省略数组括号
+db.query(dstr, 6, (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("硬删除成功");
+  }
+});
let dstr = "delete from users where id=?";
+//只有一个占位符可省略数组括号
+db.query(dstr, 6, (err, res) => {
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("硬删除成功");
+  }
+});
  • 软删除
js
let user = {
+  id:2,
+  deleted:1
+}
+let dstr  = "update users set ? where id = ?"
+db.query(dstr,[user,user.id],(err,res)=>{
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("软删除成功");
+  }
+})
let user = {
+  id:2,
+  deleted:1
+}
+let dstr  = "update users set ? where id = ?"
+db.query(dstr,[user,user.id],(err,res)=>{
+  if (err) {
+    return console.log(err.message);
+  }
+  if (res.affectedRows > 0) {
+    console.log("软删除成功");
+  }
+})

九、身份认证

1. http 协议的特性

  • 无状态性:多个请求之间相互独立,服务器不会保留每次 HTTP 请求的状态
  • 无连接:服务器挨个处理访问队列里的访问,处理完一个就关闭连接
  • 自动发送
  • 域名独立
  • 过期时限
  • 4KB 限制

注意:Cookie 不具有安全性,可以伪造,所以不要用 Cookie 保存隐私数据。

3.Session 认证

image-20220502193259029

js
const express = require('express')
+const app = express()
+
+//配置 Session 中间件
+const session = require('express-session')
+app.use(
+  session({
+    secret: 'usersession',
+    resave: false,
+    saveUninitialized: true,
+  })
+)
+
+// 托管静态页面
+app.use(express.static('./pages'))
+// 解析 POST 提交过来的表单数据
+app.use(express.urlencoded({ extended: false }))
+
+// 登录的 API 接口
+app.post('/api/login', (req, res) => {
+  // 判断用户提交的登录信息是否正确
+  if (req.body.username !== 'admin' || req.body.password !== '000000') {
+    return res.send({ status: 1, msg: '登录失败' })
+  }
+
+  //将登录成功后的用户信息,保存到 Session 中(express-session配置后才有)
+  req.session.user = req.body // 用户的信息
+  req.session.islogin = true // 用户的登录状态
+
+  res.send({ status: 0, msg: '登录成功' })
+})
+
+// 获取用户姓名的接口
+app.get('/api/username', (req, res) => {
+  //从 Session 中获取用户的名称,响应给客户端
+  if (!req.session.islogin) {
+    return res.send({ status: 1, msg: 'fail' })
+  }
+  res.send({
+    status: 0,
+    msg: 'success',
+    username: req.session.user.username,
+  })
+})
+
+// 退出登录的接口
+app.post('/api/logout', (req, res) => {
+  //清空 Session 信息
+  req.session.destroy()
+  res.send({
+    status: 0,
+    msg: '退出登录成功',
+  })
+})
+
+// 调用 app.listen 方法,指定端口号并启动web服务器
+app.listen(80, function () {
+  console.log('Express server running at http://127.0.0.1:80')
+})
const express = require('express')
+const app = express()
+
+//配置 Session 中间件
+const session = require('express-session')
+app.use(
+  session({
+    secret: 'usersession',
+    resave: false,
+    saveUninitialized: true,
+  })
+)
+
+// 托管静态页面
+app.use(express.static('./pages'))
+// 解析 POST 提交过来的表单数据
+app.use(express.urlencoded({ extended: false }))
+
+// 登录的 API 接口
+app.post('/api/login', (req, res) => {
+  // 判断用户提交的登录信息是否正确
+  if (req.body.username !== 'admin' || req.body.password !== '000000') {
+    return res.send({ status: 1, msg: '登录失败' })
+  }
+
+  //将登录成功后的用户信息,保存到 Session 中(express-session配置后才有)
+  req.session.user = req.body // 用户的信息
+  req.session.islogin = true // 用户的登录状态
+
+  res.send({ status: 0, msg: '登录成功' })
+})
+
+// 获取用户姓名的接口
+app.get('/api/username', (req, res) => {
+  //从 Session 中获取用户的名称,响应给客户端
+  if (!req.session.islogin) {
+    return res.send({ status: 1, msg: 'fail' })
+  }
+  res.send({
+    status: 0,
+    msg: 'success',
+    username: req.session.user.username,
+  })
+})
+
+// 退出登录的接口
+app.post('/api/logout', (req, res) => {
+  //清空 Session 信息
+  req.session.destroy()
+  res.send({
+    status: 0,
+    msg: '退出登录成功',
+  })
+})
+
+// 调用 app.listen 方法,指定端口号并启动web服务器
+app.listen(80, function () {
+  console.log('Express server running at http://127.0.0.1:80')
+})

Session 认证弊端:需要配合 Cookie,Cookie 不支持跨域,需要做额外配置,才能实现跨域 Session 认证。

4.JWT 认证

原理:服务端通多用户信息生成 Token,发送并保存在客户端,服务器通过还原 Token 来认证用户身份。

image-20220502195232085

JWT 组成部分:Header(头部)、Payload(有效载荷)、Signature(签名)。形式:Header.Payload.Signature

image-20220502195537066

JWT 使用

安装jsonwebtokenexpress-jwt

js
const express = require('express')
+const app = express()
+
+// 01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
+const jwt = require('jsonwebtoken')
+const expressJWT = require('express-jwt')
+
+// 允许跨域资源共享
+const cors = require('cors')
+app.use(cors())
+
+// 解析 post 表单数据的中间件
+const bodyParser = require('body-parser')
+app.use(bodyParser.urlencoded({ extended: false }))
+
+// 02:定义 secret 密钥,建议将密钥命名为 secretKey
+const secretKey = 'coder8888'
+
+// 04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
+// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
+app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\\/api\\//] }))
+
+// 登录接口
+app.post('/api/login', function (req, res) {
+  // 将 req.body 请求体中的数据,转存为 userinfo 常量
+  const userinfo = req.body
+  // 登录失败
+  if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
+    return res.send({
+      status: 400,
+      message: '登录失败!',
+    })
+  }
+  // 登录成功
+  /* 03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
+   参数1:用户的信息对象
+   参数2:加密的秘钥
+   参数3:配置对象,可以配置当前 token 的有效期
+   记住:千万不要把密码加密到 token 字符中*/
+  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
+  res.send({
+    status: 200,
+    message: '登录成功!',
+    token: tokenStr, // 要发送给客户端的 token 字符串
+  })
+})
+
+// 这是一个有权限的 API 接口
+app.get('/admin/getinfo', function (req, res) {
+  // 05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
+  console.log(req.user)
+  res.send({
+    status: 200,
+    message: '获取用户信息成功!',
+    data: req.user, // 要发送给客户端的用户信息
+  })
+})
+
+// 06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
+app.use((err, req, res, next) => {
+  // 这次错误是由 token 解析失败导致的
+  if (err.name === 'UnauthorizedError') {
+    return res.send({
+      status: 401,
+      message: '无效的token',
+    })
+  }
+  res.send({
+    status: 500,
+    message: '未知的错误',
+  })
+})
+
+
+app.listen(8888, function () {
+  console.log('Express server running at http://127.0.0.1:8888')
+})
const express = require('express')
+const app = express()
+
+// 01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
+const jwt = require('jsonwebtoken')
+const expressJWT = require('express-jwt')
+
+// 允许跨域资源共享
+const cors = require('cors')
+app.use(cors())
+
+// 解析 post 表单数据的中间件
+const bodyParser = require('body-parser')
+app.use(bodyParser.urlencoded({ extended: false }))
+
+// 02:定义 secret 密钥,建议将密钥命名为 secretKey
+const secretKey = 'coder8888'
+
+// 04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
+// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
+app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\\/api\\//] }))
+
+// 登录接口
+app.post('/api/login', function (req, res) {
+  // 将 req.body 请求体中的数据,转存为 userinfo 常量
+  const userinfo = req.body
+  // 登录失败
+  if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
+    return res.send({
+      status: 400,
+      message: '登录失败!',
+    })
+  }
+  // 登录成功
+  /* 03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
+   参数1:用户的信息对象
+   参数2:加密的秘钥
+   参数3:配置对象,可以配置当前 token 的有效期
+   记住:千万不要把密码加密到 token 字符中*/
+  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
+  res.send({
+    status: 200,
+    message: '登录成功!',
+    token: tokenStr, // 要发送给客户端的 token 字符串
+  })
+})
+
+// 这是一个有权限的 API 接口
+app.get('/admin/getinfo', function (req, res) {
+  // 05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
+  console.log(req.user)
+  res.send({
+    status: 200,
+    message: '获取用户信息成功!',
+    data: req.user, // 要发送给客户端的用户信息
+  })
+})
+
+// 06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
+app.use((err, req, res, next) => {
+  // 这次错误是由 token 解析失败导致的
+  if (err.name === 'UnauthorizedError') {
+    return res.send({
+      status: 401,
+      message: '无效的token',
+    })
+  }
+  res.send({
+    status: 500,
+    message: '未知的错误',
+  })
+})
+
+
+app.listen(8888, function () {
+  console.log('Express server running at http://127.0.0.1:8888')
+})
`,112),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.lean.js" "b/assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.lean.js" new file mode 100644 index 00000000..10b299da --- /dev/null +++ "b/assets/BackEnd_NodeJS_Node\345\255\246\344\271\240\347\254\224\350\256\260.md.f1b234ff.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/Node学习笔记.md","filePath":"BackEnd/NodeJS/Node学习笔记.md"}'),p={name:"BackEnd/NodeJS/Node学习笔记.md"},o=l("",112),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.js" "b/assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.js" new file mode 100644 index 00000000..692dd6e0 --- /dev/null +++ "b/assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.js" @@ -0,0 +1,145 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"Node 简单上传文件","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/Node简单上传文件.md","filePath":"BackEnd/NodeJS/Node简单上传文件.md"}'),p={name:"BackEnd/NodeJS/Node简单上传文件.md"},o=l(`

Node 简单上传文件

Vue 前端代码

vue
<script setup>
+import axios from 'axios'
+const onUpload = (e) => {
+  let formData = new FormData()
+  formData.append('fileName', e.target.files[0]) //fileName:后端接收的参数名
+  console.log('[ formData ]-6', formData)
+  axios.post('http://localhost:3000/upload/postFile', formData, {
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  }).then(res => {
+    console.log('[ res ]', res)
+  }).catch(err => {
+    console.log('[ err ]', err)
+  })
+}
+</script>
+
+<template>
+  <input type="file" @change="onUpload">
+</template>
<script setup>
+import axios from 'axios'
+const onUpload = (e) => {
+  let formData = new FormData()
+  formData.append('fileName', e.target.files[0]) //fileName:后端接收的参数名
+  console.log('[ formData ]-6', formData)
+  axios.post('http://localhost:3000/upload/postFile', formData, {
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  }).then(res => {
+    console.log('[ res ]', res)
+  }).catch(err => {
+    console.log('[ err ]', err)
+  })
+}
+</script>
+
+<template>
+  <input type="file" @change="onUpload">
+</template>

Express 后端代码

js
const express = require("express");
+const multer = require("multer");
+const fs = require("fs");
+const path = require("path");
+
+const app = express();
+const router = express.Router();
+app.use("/upload", router);
+
+const upload = multer({
+  storage: multer.diskStorage({
+    //设置文件存储位置
+    destination: (req, file, cb) => {
+      let date = new Date();
+      let year = date.getFullYear();
+      let month = (date.getMonth() + 1).toString().padStart(2, "0");
+      let day = date.getDate();
+      let dir = "./public/uploads/" + year + month + day;
+      //判断目录是否存在,没有则创建
+      if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
+      //dir就是上传文件存放的目录
+      cb(null, dir);
+    }, //设置文件名称
+    filename: (req, file, cb) => {
+      // 获取原来的文件名
+      let oldName = file.originalname;
+      //获取文件前缀
+      let prefix = oldName.startsWith(".") ? oldName : oldName.split(".")[0];
+      let fileName =
+        prefix + "-" + Date.now() + path.extname(file.originalname);
+      //fileName就是上传文件的文件名
+      cb(null, fileName);
+    },
+  }),
+});
+ //访问地址为:localhost:3000/upload/index,操作界面,使用 Vue 时可不需要这个接口
+router.get("/index", (req, res) => {
+  //接口地址为:localhost:3000/upload/postFile ,input的name属性值为imgFile和upload.single("imgFile")对应
+  res.send(\`
+  <form action="http://localhost:3000/upload/postFile" method="post" enctype="multipart/form-data">
+  <input id="postFile" type="file" name="fileName" multiple>
+  <button type="submit">上传</button>
+</form>\`);
+});
+router.post("/postFile", upload.single("fileName"), (req, res, next) => {
+  res.json({
+    file: req.file,
+  });
+});
+
+app.listen(3000, () => {
+  console.log("server is running at http://localhost:3000");
+});
const express = require("express");
+const multer = require("multer");
+const fs = require("fs");
+const path = require("path");
+
+const app = express();
+const router = express.Router();
+app.use("/upload", router);
+
+const upload = multer({
+  storage: multer.diskStorage({
+    //设置文件存储位置
+    destination: (req, file, cb) => {
+      let date = new Date();
+      let year = date.getFullYear();
+      let month = (date.getMonth() + 1).toString().padStart(2, "0");
+      let day = date.getDate();
+      let dir = "./public/uploads/" + year + month + day;
+      //判断目录是否存在,没有则创建
+      if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
+      //dir就是上传文件存放的目录
+      cb(null, dir);
+    }, //设置文件名称
+    filename: (req, file, cb) => {
+      // 获取原来的文件名
+      let oldName = file.originalname;
+      //获取文件前缀
+      let prefix = oldName.startsWith(".") ? oldName : oldName.split(".")[0];
+      let fileName =
+        prefix + "-" + Date.now() + path.extname(file.originalname);
+      //fileName就是上传文件的文件名
+      cb(null, fileName);
+    },
+  }),
+});
+ //访问地址为:localhost:3000/upload/index,操作界面,使用 Vue 时可不需要这个接口
+router.get("/index", (req, res) => {
+  //接口地址为:localhost:3000/upload/postFile ,input的name属性值为imgFile和upload.single("imgFile")对应
+  res.send(\`
+  <form action="http://localhost:3000/upload/postFile" method="post" enctype="multipart/form-data">
+  <input id="postFile" type="file" name="fileName" multiple>
+  <button type="submit">上传</button>
+</form>\`);
+});
+router.post("/postFile", upload.single("fileName"), (req, res, next) => {
+  res.json({
+    file: req.file,
+  });
+});
+
+app.listen(3000, () => {
+  console.log("server is running at http://localhost:3000");
+});

可以借助接口调试工具测试或直接访问:http://localhost:3000/upload/index

image-20230213141712478

image-20230213141820443

`,8),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.lean.js" "b/assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.lean.js" new file mode 100644 index 00000000..ff275f1a --- /dev/null +++ "b/assets/BackEnd_NodeJS_Node\347\256\200\345\215\225\344\270\212\344\274\240\346\226\207\344\273\266.md.faa27b4e.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"Node 简单上传文件","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/NodeJS/Node简单上传文件.md","filePath":"BackEnd/NodeJS/Node简单上传文件.md"}'),p={name:"BackEnd/NodeJS/Node简单上传文件.md"},o=l("",8),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.js" "b/assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.js" new file mode 100644 index 00000000..e0c4e9d0 --- /dev/null +++ "b/assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.js" @@ -0,0 +1,221 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const d=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/Server/Docker学习笔记.md","filePath":"BackEnd/Server/Docker学习笔记.md"}'),p={name:"BackEnd/Server/Docker学习笔记.md"},o=l(`

一、解决痛点

  1. 环境不一致
  2. 版本不一样
  3. 配置不一致,配置费力费时

把源码+配置+环境+版本打包成镜像,装载在Dokcer容器引擎上,达到跨平台无缝接轨运作。 一次镜像,处处运行,从搬家到搬楼。

二、优点和应用

  1. 便捷升级和快速扩容
  2. 更简单的系统运维
  3. 镜像小、更高效的计算资源
  4. 更快的应用交付和平缓迁移
  5. 利用宿主机内核,不需要加载操作系统OS内核

三、基本组成

  1. 镜像:一个只读的模板,用于创建容器,一个镜像可以创建多个容器。
  2. 容器:镜像创建出来的虚拟化运行环境容器实例(简易的Linux环境)。
  3. 仓库:集中存放镜像的场所,分为公开库和私有库。

四、工作原理

五、CentOS安装Docker

bash
sudo yum install -y yum-utils
+yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
+sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
+docker version
+systemctl start docker #启动
+ps -ef | grep docker
+docker run hello-world #测试
sudo yum install -y yum-utils
+yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
+sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
+docker version
+systemctl start docker #启动
+ps -ef | grep docker
+docker run hello-world #测试

六、阿里云镜像加速

参考教程

七、常用命令

1. Docker

bash
systemctl enable docker #开机启动
+docker system df #负载查看
systemctl enable docker #开机启动
+docker system df #负载查看

2. 镜像

bash
docker images #展示本地镜像 -a 所有,-q只显示ID
+docker search mongo #搜索镜像
+docker search redis --limit 5 #展示Stars排名前五条
+docker pull 镜像名[:TAG]  #下载镜像,没有版本号默认最新
+docker rmi -f hello-world #强制删除镜像
docker images #展示本地镜像 -a 所有,-q只显示ID
+docker search mongo #搜索镜像
+docker search redis --limit 5 #展示Stars排名前五条
+docker pull 镜像名[:TAG]  #下载镜像,没有版本号默认最新
+docker rmi -f hello-world #强制删除镜像

虚悬镜像:构建或删除过程中产生的仓库名和标签都为none的镜像,没啥用建议删除 docker image ls -f dangling=true 删除:docker image prune

生成新镜像

bash
agt-get update
+apt-get -y install vim
+docker commit -m="vim is ok" -a="fxj" 容器id myubt:1.1
agt-get update
+apt-get -y install vim
+docker commit -m="vim is ok" -a="fxj" 容器id myubt:1.1

本地镜像推送到阿里云

bash
#发布和拉取
+docker login --username=yunzhishangfxj registry.cn-hangzhou.aliyuncs.com
+docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker push registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker run -it registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:1.1  /bin/bash #记得带版本
#发布和拉取
+docker login --username=yunzhishangfxj registry.cn-hangzhou.aliyuncs.com
+docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker push registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
+docker run -it registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:1.1  /bin/bash #记得带版本

3. 容器

bash
docker ps #列出正在运行容器 -a -s
+docker run -it --name="ub01"  ubuntu /bin/bash 
+#-p: 外部主机端口:docker容器端口 -P:随机分配主机端口映射到内部容器端口
+#-i:交互式 -t:输出伪终端 -d:后台运行 --name="容器名" /bin/bash:指定命令解释器
+
+exit #退出,ctrl+q+p:退出但不停止
+docker exec -it 容器id /bin/bash #重新进容器,exit退出不会停止容器
+
+docker start 容器id或容器名
+docker restart 
+docker stop
+docker kill #强制停止
+
+docker rm 容器id或容器名 #删除已停止容器 、未停止 -f 强制删除
+docker rm 
+docker rm -f $(docker ps -a -q) 
+docker ps -a -q | xargs docker rm #一次性删除多个再运行的
docker ps #列出正在运行容器 -a -s
+docker run -it --name="ub01"  ubuntu /bin/bash 
+#-p: 外部主机端口:docker容器端口 -P:随机分配主机端口映射到内部容器端口
+#-i:交互式 -t:输出伪终端 -d:后台运行 --name="容器名" /bin/bash:指定命令解释器
+
+exit #退出,ctrl+q+p:退出但不停止
+docker exec -it 容器id /bin/bash #重新进容器,exit退出不会停止容器
+
+docker start 容器id或容器名
+docker restart 
+docker stop
+docker kill #强制停止
+
+docker rm 容器id或容器名 #删除已停止容器 、未停止 -f 强制删除
+docker rm 
+docker rm -f $(docker ps -a -q) 
+docker ps -a -q | xargs docker rm #一次性删除多个再运行的

启动守护式

bash
docker run -it #前台交互启动
+docker run -d  #后台守护启动
docker run -it #前台交互启动
+docker run -d  #后台守护启动

查看容器日志

bash
docker logs 容器id #查看容器日志
+docker inspect  容器id #查看容器内部细节
docker logs 容器id #查看容器日志
+docker inspect  容器id #查看容器内部细节

容器备份到主机

bash
docker cp 容器id:容器文件路径 目的主机路径  #备份文件
+docker export 容器id > xxx.tar	 #备份整个容器
+cat ub.tar | docker import - 恢复后的镜像名  #从tar包中恢复成镜像
+docker run -it  镜像id /bin/bash #重新恢复容器
docker cp 容器id:容器文件路径 目的主机路径  #备份文件
+docker export 容器id > xxx.tar	 #备份整个容器
+cat ub.tar | docker import - 恢复后的镜像名  #从tar包中恢复成镜像
+docker run -it  镜像id /bin/bash #重新恢复容器

容器卷

八、Dockerfile编写

dockerfile
#基础镜像,基于什么镜像什么版本作为模版 
+From xxx:1.1 
+
+#构建参数,运行时无效,可以构建时候临时修改变量(docker build --build-arg B=10)
+ARG
+
+#定义运行时环境变量,运行时一直生效后续可以引用, ARG变量可以传递给ENV
+ENV NGINX_HOME /usr/local/nginx
+
+#指定进入容器后的默认工作目录(落脚点)
+WORKDIR $NGINX_HOME
+
+#将宿主机的文件拷贝到镜像
+COPY <src>  <dest>
+
+#将主机目录下的文件拷贝到镜像,且会自动处理URL和解压tar压缩包
+ADD 
+
+#Dockerfile构建时运行(docker build), 
+RUN 
+
+#容器启动后(docker run)执行的脚本,多个命令时只会生效最后一个???
+#会被docker run之后的参数替换(/bin/bash)
+CMD  ["/etc/nginx/nginx.conf"]
+
+#类似CMD,但是不会(docker run)后面命令覆盖,而且可以接收CMD传的参数
+ENTRYPOINT ["nginx","-c"] ==> nginx -c /etc/nginx/nginx.conf
+#docker run nginx:test -c /etc/nginx/new.conf ==> nginx -c /etc/nginx/new.conf
+一般语句为:
+FROM WORKDIR COPY-ADD RUN CMD-ENTRYPOINT
+
+
+
+#暴露镜像的指定端口
+EXPOSE 9999
+
+#指定容器卷
+VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
+
+#指定元数据,标识容器便于查找
+LABEL 
+
+#当前镜像构建的时候不会执行,基于当前镜像的镜像去构建的时候才会在FROM后执行
+ONBUILD 
+
+#指定容器使用什么信号,一般指定信号名
+STOPSIGNAL
+
+#检查容易的健康状态
+HEALTHCHECK 
+
+#指定命令解释器 linux为/bin/sh,windows为cmd
+SHELL 
+
+#用于指定RUN CMD等指令运行时的用户身份,不指定是root(用户名:用户组 或 USER 用户id:组id)
+USER
#基础镜像,基于什么镜像什么版本作为模版 
+From xxx:1.1 
+
+#构建参数,运行时无效,可以构建时候临时修改变量(docker build --build-arg B=10)
+ARG
+
+#定义运行时环境变量,运行时一直生效后续可以引用, ARG变量可以传递给ENV
+ENV NGINX_HOME /usr/local/nginx
+
+#指定进入容器后的默认工作目录(落脚点)
+WORKDIR $NGINX_HOME
+
+#将宿主机的文件拷贝到镜像
+COPY <src>  <dest>
+
+#将主机目录下的文件拷贝到镜像,且会自动处理URL和解压tar压缩包
+ADD 
+
+#Dockerfile构建时运行(docker build), 
+RUN 
+
+#容器启动后(docker run)执行的脚本,多个命令时只会生效最后一个???
+#会被docker run之后的参数替换(/bin/bash)
+CMD  ["/etc/nginx/nginx.conf"]
+
+#类似CMD,但是不会(docker run)后面命令覆盖,而且可以接收CMD传的参数
+ENTRYPOINT ["nginx","-c"] ==> nginx -c /etc/nginx/nginx.conf
+#docker run nginx:test -c /etc/nginx/new.conf ==> nginx -c /etc/nginx/new.conf
+一般语句为:
+FROM WORKDIR COPY-ADD RUN CMD-ENTRYPOINT
+
+
+
+#暴露镜像的指定端口
+EXPOSE 9999
+
+#指定容器卷
+VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
+
+#指定元数据,标识容器便于查找
+LABEL 
+
+#当前镜像构建的时候不会执行,基于当前镜像的镜像去构建的时候才会在FROM后执行
+ONBUILD 
+
+#指定容器使用什么信号,一般指定信号名
+STOPSIGNAL
+
+#检查容易的健康状态
+HEALTHCHECK 
+
+#指定命令解释器 linux为/bin/sh,windows为cmd
+SHELL 
+
+#用于指定RUN CMD等指令运行时的用户身份,不指定是root(用户名:用户组 或 USER 用户id:组id)
+USER

九、Docker网络

bash
docker network ls #查看网络
+docker network inspect 网络名 #查看网络源数据
+docker network rm 网络名 #删除网络
+docker network create 网络名 #新建网络
+docker network inspect bridge | grep docker0 #查看网卡信息
+
+# --network 不指定默认就是网桥模式
+#host主机模式(不能指定端口,共享宿主机的ip,没有自己的ip,http://宿主机ip:端口)
+docker run -d --network host --name 容器名 镜像名
+
+docker run -d --network none --name 容器名 镜像名 #只有lo网卡
docker network ls #查看网络
+docker network inspect 网络名 #查看网络源数据
+docker network rm 网络名 #删除网络
+docker network create 网络名 #新建网络
+docker network inspect bridge | grep docker0 #查看网卡信息
+
+# --network 不指定默认就是网桥模式
+#host主机模式(不能指定端口,共享宿主机的ip,没有自己的ip,http://宿主机ip:端口)
+docker run -d --network host --name 容器名 镜像名
+
+docker run -d --network none --name 容器名 镜像名 #只有lo网卡

共用网卡

bash
docker run -d --network container:另一个容器名 --name 容器名 /bin/bash 镜像名  
+#共用的容器关闭,这个容器网卡也没有啦
docker run -d --network container:另一个容器名 --name 容器名 /bin/bash 镜像名  
+#共用的容器关闭,这个容器网卡也没有啦

自定义网络

bash
#启动两个网桥模式容器
+docker run -d -p 8081:8080 --name tomcat81 tomcat
+docker run -d -p 8082:8080 --name tomcat82 tomcat
+
+#两个ip可以相互ping通,痛点:按域名ping不通
#启动两个网桥模式容器
+docker run -d -p 8081:8080 --name tomcat81 tomcat
+docker run -d -p 8082:8080 --name tomcat82 tomcat
+
+#两个ip可以相互ping通,痛点:按域名ping不通
bash
docker run -d -p 8081:8080 --network my_network --name tomcat81 tomcat
+docker run -d -p 8082:8080 --network my_network --name tomcat82 tomcat
+#ip、域名互ping都能通(维护好主机和ip的关系)
docker run -d -p 8081:8080 --network my_network --name tomcat81 tomcat
+docker run -d -p 8082:8080 --network my_network --name tomcat82 tomcat
+#ip、域名互ping都能通(维护好主机和ip的关系)

十、容器编排

意义:集中快速管理多个容器

1. 安装Compose

bash
curl -SL https://github.com/docker/compose/releases/download/v2.14.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
curl -SL https://github.com/docker/compose/releases/download/v2.14.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

2. 常用命令

3. 安装 Portainer

`,49),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{d as __pageData,C as default}; diff --git "a/assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.lean.js" "b/assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.lean.js" new file mode 100644 index 00000000..aea5ffe2 --- /dev/null +++ "b/assets/BackEnd_Server_Docker\345\255\246\344\271\240\347\254\224\350\256\260.md.d29feca6.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const d=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/Server/Docker学习笔记.md","filePath":"BackEnd/Server/Docker学习笔记.md"}'),p={name:"BackEnd/Server/Docker学习笔记.md"},o=l("",49),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{d as __pageData,C as default}; diff --git "a/assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.js" "b/assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.js" new file mode 100644 index 00000000..72736748 --- /dev/null +++ "b/assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.js" @@ -0,0 +1,11 @@ +import{_ as s,o as a,c as n,Q as t}from"./chunks/framework.c53372a0.js";const D=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/Server/Nginx学习笔记.md","filePath":"BackEnd/Server/Nginx学习笔记.md"}'),l={name:"BackEnd/Server/Nginx学习笔记.md"},e=t(`

一、Nginx安装

1.安装命令

Ubuntuapt install nginx
CentOS(Red Hat系列)yum install nginx

2.Linux目录结构

3.基础命令

nginx -v/nginx -V查看nginx版本等信息
systemctl start/stop nginx启动/停止nginx
systemctl status nginx查看nginx运行状态
ps -ef | grep nginx查看nginx进程
kill -QUIT 进程号
kill -TERM 进程号从容停止
kill -TERM 进程号
kill -INT 进程号快速停止
pkill -9 nginx强制停止

编写配置

bash
nginx -t	#检查配置文件有没有问题
+grep -Ei  "\\{|\\}"   nginx.conf #检查配置文件括号配对问题
+nginx -s reload #重载配置
nginx -t	#检查配置文件有没有问题
+grep -Ei  "\\{|\\}"   nginx.conf #检查配置文件括号配对问题
+nginx -s reload #重载配置

日志分析器

netstat命令

curl命令

CentOS7联网

bash
ip a #查看网卡
+cd /etc/sysconfig/network-scripts
+vi ifcfg-ens160 #把ONBOOT=no ===> 改为yes
+systemctl restart network #重启网络
ip a #查看网卡
+cd /etc/sysconfig/network-scripts
+vi ifcfg-ens160 #把ONBOOT=no ===> 改为yes
+systemctl restart network #重启网络
`,14),o=[e];function p(r,c,i,d,y,h){return a(),n("div",null,o)}const g=s(l,[["render",p]]);export{D as __pageData,g as default}; diff --git "a/assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.lean.js" "b/assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.lean.js" new file mode 100644 index 00000000..21053ba4 --- /dev/null +++ "b/assets/BackEnd_Server_Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md.9d658cc4.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as t}from"./chunks/framework.c53372a0.js";const D=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"BackEnd/Server/Nginx学习笔记.md","filePath":"BackEnd/Server/Nginx学习笔记.md"}'),l={name:"BackEnd/Server/Nginx学习笔记.md"},e=t("",14),o=[e];function p(r,c,i,d,y,h){return a(),n("div",null,o)}const g=s(l,[["render",p]]);export{D as __pageData,g as default}; diff --git "a/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.js" "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.js" new file mode 100644 index 00000000..d0c881b3 --- /dev/null +++ "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.js" @@ -0,0 +1,351 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"Angular基础总结一","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Angular/Angular基础总结一.md","filePath":"Framework/Angular/Angular基础总结一.md"}'),p={name:"Framework/Angular/Angular基础总结一.md"},o=l(`

Angular基础总结一

一、NgModule

WARNING

被@NgModule所装饰的类被称为angular module

@NgModule元数据

  • declarations —— 该模块的依赖项(该模块用到的组件、指令、管道)。
  • imports —— 导入其他的ngModule。
  • providers —— 提供各种服务。
  • bootstrap —— 根组件,Angular 创建它并插入 index.html 宿主页面

declarations 数组

js
1.模块中使用的组件必须先在declarations 数组中声名
+2.一个组件只能被一个模块声名
+3.在declarations中的组件默认只能在当前模块中使用在其他模块使用必须exports导出
1.模块中使用的组件必须先在declarations 数组中声名
+2.一个组件只能被一个模块声名
+3.在declarations中的组件默认只能在当前模块中使用在其他模块使用必须exports导出

imports 数组

js
1.只会出现在@NgModule装饰器中
+2.模块想要正常工作除了本身的依赖项(declarations)还可能需要其他模块导出的依赖项
+3.只要是angular module都可以导入imports数组中比如ng内置第三方自定义的模块
1.只会出现在@NgModule装饰器中
+2.模块想要正常工作除了本身的依赖项(declarations)还可能需要其他模块导出的依赖项
+3.只要是angular module都可以导入imports数组中比如ng内置第三方自定义的模块

providers 数组

js
该数组为当前模块提供一系列服务
该数组为当前模块提供一系列服务

bootstrap 数组

js
应用是通过引导根模块 AppModule 来启动的引导过程还会创建 bootstrap 数组中列出的组件并把它们逐个插入到浏览器的 DOM 
+该数组中的每个组件都作为组件树的根根组件),后续所有组件都是基于根组件的(如图)
+虽然也可以在宿主页面中放多个组件但是大多数应用只有一个组件树并且只从一个根组件开始引导
+这个根组件通常叫做 AppComponent并且位于根模块的 bootstrap 数组中
应用是通过引导根模块 AppModule 来启动的引导过程还会创建 bootstrap 数组中列出的组件并把它们逐个插入到浏览器的 DOM 
+该数组中的每个组件都作为组件树的根根组件),后续所有组件都是基于根组件的(如图)
+虽然也可以在宿主页面中放多个组件但是大多数应用只有一个组件树并且只从一个根组件开始引导
+这个根组件通常叫做 AppComponent并且位于根模块的 bootstrap 数组中
结构图

二、模板基础语法

1. 模板表达式

模版中还可以写些简单的逻辑,比如判断或运算

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`<h1>{{title}}</h1>
+             <p> sum : {{1 + 1}}</p>
+             <p>price: {{price * 0.7}}</p>
+             <p>与方法结合: {{price * 0.7 + getVal()}}.</p>
+\`,    //内联模板
+  styles: [\`h1 { color: yellow }\`]    //内联样式
+})    
+export class AppComponent {
+  title = 'my-angular-title';
+  price = 30
+  getVal(): number {
+        return 33;
+  }
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`<h1>{{title}}</h1>
+             <p> sum : {{1 + 1}}</p>
+             <p>price: {{price * 0.7}}</p>
+             <p>与方法结合: {{price * 0.7 + getVal()}}.</p>
+\`,    //内联模板
+  styles: [\`h1 { color: yellow }\`]    //内联样式
+})    
+export class AppComponent {
+  title = 'my-angular-title';
+  price = 30
+  getVal(): number {
+        return 33;
+  }
+}

模板表达式遵循原则:

  • 非常简单
  • 执行迅速
  • 没有可见的副作用(即模版中的逻辑不能改变组件的变量)

2. 模板来源

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.scss'] //注意: styleUrls
+})
+export class AppComponent {
+
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.scss'] //注意: styleUrls
+})
+export class AppComponent {
+
+}

3. 属性绑定

html
<img src="../assets/images/zorro.jpg" alt="madao" /><!-- 静态绑定-->
+<img [src]="zorroSrc" alt="zorro" />     <!-- 简写形式-->
+<img bind-src="zorroSrc" alt="zorro" /> <!-- 完整形式-->
+<button [disabled]="isDisabled">click</button>
+<!-- zorroSrc、zorro、isDisabled均为变量 -->
<img src="../assets/images/zorro.jpg" alt="madao" /><!-- 静态绑定-->
+<img [src]="zorroSrc" alt="zorro" />     <!-- 简写形式-->
+<img bind-src="zorroSrc" alt="zorro" /> <!-- 完整形式-->
+<button [disabled]="isDisabled">click</button>
+<!-- zorroSrc、zorro、isDisabled均为变量 -->

4. 自定义属性绑定

html
<p [attr.data-title]="customTitle">一行文字</p>
+<p [attr.title]="customTitle">测试自定义标题属性</p>
<p [attr.data-title]="customTitle">一行文字</p>
+<p [attr.title]="customTitle">测试自定义标题属性</p>

5. 插值表达式属性绑定

html
<img src="{{ picUrl }}" alt="{{ picInfo }}" /> <!-- 不常用 -->
<img src="{{ picUrl }}" alt="{{ picInfo }}" /> <!-- 不常用 -->

6. 单个class样式绑定

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <button type="button" class="btn" [class.btn-primary]="theme === 'primary'">Primary</button>
+      <button type="button" class="btn" [class.btn-secondary]="true">secondary</button>
+      <button type="button" class="btn" [class.btn-success]="isSuccess">success</button>
+      <button type="button" class="btn" [class.btn-danger]="'啦啦啦'">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="0">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="undefined">danger</button>
+    \`,
+  styles: []
+})
+export class AppComponent {
+    theme = 'primary';
+    isSuccess = true;
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <button type="button" class="btn" [class.btn-primary]="theme === 'primary'">Primary</button>
+      <button type="button" class="btn" [class.btn-secondary]="true">secondary</button>
+      <button type="button" class="btn" [class.btn-success]="isSuccess">success</button>
+      <button type="button" class="btn" [class.btn-danger]="'啦啦啦'">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="0">danger</button>
+      <button type="button" class="btn" [class.btn-danger]="undefined">danger</button>
+    \`,
+  styles: []
+})
+export class AppComponent {
+    theme = 'primary';
+    isSuccess = true;
+}

7. 绑定多个class

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <button type="button" [class]="btnCls">btnCls</button>
+      <button type="button" [class]="btnCls2">btnCls2</button>
+      <button type="button" [class]="btnCls3">btnCls3</button>
+
+      <!-- 也可以用内置指令ngClass -->
+      <button type="button" [ngClass]="btnCls">btnCls</button>
+      <button type="button" [ngClass]="btnCls2">btnCls2</button>
+      <button type="button" [ngClass]="btnCls3">btnCls3</button>
+    \`,
+  styles: []
+})
+export class AppComponent {
+    btnCls = 'btn btn-primary';
+    btnCls2 = ['btn', 'btn-success'];
+    btnCls3 = {
+      btn: true,
+      'btn-info': true
+    };
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <button type="button" [class]="btnCls">btnCls</button>
+      <button type="button" [class]="btnCls2">btnCls2</button>
+      <button type="button" [class]="btnCls3">btnCls3</button>
+
+      <!-- 也可以用内置指令ngClass -->
+      <button type="button" [ngClass]="btnCls">btnCls</button>
+      <button type="button" [ngClass]="btnCls2">btnCls2</button>
+      <button type="button" [ngClass]="btnCls3">btnCls3</button>
+    \`,
+  styles: []
+})
+export class AppComponent {
+    btnCls = 'btn btn-primary';
+    btnCls2 = ['btn', 'btn-success'];
+    btnCls3 = {
+      btn: true,
+      'btn-info': true
+    };
+}

8. 绑定单个style

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <p [style.color]="'##f60'">一段文字</p>
+      <p [style.height]="'50px'" [style.border]="'1px solid'">设置高度</p>
+      <p [style.height.px]="50" [style.border]="'1px solid'">设置高度</p>
+    \`,
+  styles: []
+})
+export class AppComponent {}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <p [style.color]="'##f60'">一段文字</p>
+      <p [style.height]="'50px'" [style.border]="'1px solid'">设置高度</p>
+      <p [style.height.px]="50" [style.border]="'1px solid'">设置高度</p>
+    \`,
+  styles: []
+})
+export class AppComponent {}

9. 绑定多个style

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <p [style]="style1">style1</p>
+      <p [style]="style2">style2</p>
+      <p [style]="style3">style3</p>
+
+      <!-- 内置指令ngStyle绑定, 不推荐 -->
+      <!--  <p [ngStyle]="style1">style1</p>-->
+      <!--  <p [ngStyle]="style2">style2</p>-->
+
+      <!-- ngStyle只接收对象 -->
+      <p [ngStyle]="style3">style3</p>
+    \`,
+  styles: []
+})
+export class AppComponent {
+  style1 = 'width: 200px;height: 50px;text-align: center;border: 1px solid;';
+  style2 = ['width', '200px', 'height', '50px', 'text-align', 'center', 'border', '1px solid']; // 有问题
+  style3 = {
+    width: '200px',
+    height: '50px',
+    'text-align': 'center',
+    border: '1px solid'
+  };
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <p [style]="style1">style1</p>
+      <p [style]="style2">style2</p>
+      <p [style]="style3">style3</p>
+
+      <!-- 内置指令ngStyle绑定, 不推荐 -->
+      <!--  <p [ngStyle]="style1">style1</p>-->
+      <!--  <p [ngStyle]="style2">style2</p>-->
+
+      <!-- ngStyle只接收对象 -->
+      <p [ngStyle]="style3">style3</p>
+    \`,
+  styles: []
+})
+export class AppComponent {
+  style1 = 'width: 200px;height: 50px;text-align: center;border: 1px solid;';
+  style2 = ['width', '200px', 'height', '50px', 'text-align', 'center', 'border', '1px solid']; // 有问题
+  style3 = {
+    width: '200px',
+    height: '50px',
+    'text-align': 'center',
+    border: '1px solid'
+  };

样式优先级

1.某个类或样式绑定越具体,它的优先级就越高

2.绑定总是优先于静态属性

10. 绑定事件

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <button (click)="onClick()">CLICK</button>
+       <button  (click)="onClick1($event)">Primary</button>
+    \`,
+  styles: []
+})
+export class AppComponent {
+    onClick() {
+      console.log('onClick');
+    } 
+    onClick1(event: MouseEvent) {
+        console.log('onClick1', event.target);
+    } 
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+      <button (click)="onClick()">CLICK</button>
+       <button  (click)="onClick1($event)">Primary</button>
+    \`,
+  styles: []
+})
+export class AppComponent {
+    onClick() {
+      console.log('onClick');
+    } 
+    onClick1(event: MouseEvent) {
+        console.log('onClick1', event.target);
+    } 
+}

11. 输入与输出属性

输入属性:用于父组件传值给子组件(父传子) @Input()

输出属性:用于子组件传值给父组件(子传父)@Output()

输入属性@Input

📝父组件

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+     <app-mycpn [item]="currentItem"></app-mycpn>
+     <!-- <app-mycpn item="我是传入的字符串"></app-mycpn>--> <!--静态属性可不用[]包裹 -->
+
+  \`,
+})
+export class AppComponent {
+  currentItem = 'Television';
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+     <app-mycpn [item]="currentItem"></app-mycpn>
+     <!-- <app-mycpn item="我是传入的字符串"></app-mycpn>--> <!--静态属性可不用[]包裹 -->
+
+  \`,
+})
+export class AppComponent {
+  currentItem = 'Television';
+}

📝子组件

typescript
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: \`<p>
+               Today's item: {{item}}
+             </p>\`
+})
+export class MycpnComponent  {
+  @Input() item: string;   
+ //@Input('aliasItem') item: string; 提供别名,item变量只可以在本组件使用
+ //相当于对父组件传入的aliasItem变量进行重命名
+}
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: \`<p>
+               Today's item: {{item}}
+             </p>\`
+})
+export class MycpnComponent  {
+  @Input() item: string;   
+ //@Input('aliasItem') item: string; 提供别名,item变量只可以在本组件使用
+ //相当于对父组件传入的aliasItem变量进行重命名
+}

输出属性@Output()

📝父组件

typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+     <app-mycpn  (newItemEvent)="addItem($event)"></app-mycpn>
+  \`,
+})
+export class AppComponent {
+   items = ['item1', 'item2', 'item3', 'item4'];
+    addItem(newItem: string) {
+      this.items.push(newItem);
+    }
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+     <app-mycpn  (newItemEvent)="addItem($event)"></app-mycpn>
+  \`,
+})
+export class AppComponent {
+   items = ['item1', 'item2', 'item3', 'item4'];
+    addItem(newItem: string) {
+      this.items.push(newItem);
+    }
+}

📝子组件

typescript
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: \`<label>Add an item: <input ##newItem></label>
+             <button (click)="addNewItem(newItem.value)">Add to parent's list</button>\`
+})
+export class MycpnComponent  {
+  @Output() newItemEvent = new EventEmitter<string>();
+  // @Output('newItem') newItemEvent = new EventEmitter<string>();
+  addNewItem(value: string) {
+    this.newItemEvent.emit(value);
+  }
+}
import { Component, Input } from '@angular/core';
+@Component({
+  selector: 'app-mycpn',
+  template: \`<label>Add an item: <input ##newItem></label>
+             <button (click)="addNewItem(newItem.value)">Add to parent's list</button>\`
+})
+export class MycpnComponent  {
+  @Output() newItemEvent = new EventEmitter<string>();
+  // @Output('newItem') newItemEvent = new EventEmitter<string>();
+  addNewItem(value: string) {
+    this.newItemEvent.emit(value);
+  }
+}

还可以元数据中声名输入、输出属性。(不推荐)

三、组件样式

宿主选择器

:host选择是是把宿主元素作为目标的唯一方式

md
它选中的是组件模板标签,比如<app-child></app-child>,相当于在父组件的style中使用标签选择器选择 app-child {}
它选中的是组件模板标签,比如<app-child></app-child>,相当于在父组件的style中使用标签选择器选择 app-child {}

当宿主标签上有 active 类名时生效

css
:host(.active) {
+  border-width: 3px solid ##ccc;
+}
:host(.active) {
+  border-width: 3px solid ##ccc;
+}

祖先选择器

当某个祖先元素有 CSS 类 light 时,才会把 background-color 样式应用到组件内部的所有 .title 元素中,找到根元素(html标签)为止

css
:host-context(.light) .title {
+      background-color: ##bfa;
+}
:host-context(.light) .title {
+      background-color: ##bfa;
+}

样式模块化

在 @Component 的元数据中指定的样式只会对该组件的模板生效

组件的样式不会影响到子组件中的模板

组件的样式不会影响到投影内容

视图封装模式

ShadowDom -- 不进不出,没有样式能进来,组件样式出不去, 就自己玩

Emulated --只进不出, 默认选项,全局样式能进来,组件样式出不去

None -- 能进能出,此时组件的样式是全局生效的,注意与其他组件发生样式冲突,(对父组件样式也能生效)

`,64),t=[o];function e(c,r,y,i,A,D){return n(),a("div",null,t)}const u=s(p,[["render",e]]);export{C as __pageData,u as default}; diff --git "a/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.lean.js" "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.lean.js" new file mode 100644 index 00000000..6527f5ee --- /dev/null +++ "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.25af9886.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"Angular基础总结一","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Angular/Angular基础总结一.md","filePath":"Framework/Angular/Angular基础总结一.md"}'),p={name:"Framework/Angular/Angular基础总结一.md"},o=l("",64),t=[o];function e(c,r,y,i,A,D){return n(),a("div",null,t)}const u=s(p,[["render",e]]);export{C as __pageData,u as default}; diff --git "a/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.js" "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.js" new file mode 100644 index 00000000..977be888 --- /dev/null +++ "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.js" @@ -0,0 +1,861 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Angular/Angular基础总结三.md","filePath":"Framework/Angular/Angular基础总结三.md"}'),p={name:"Framework/Angular/Angular基础总结三.md"},o=l(`

组件投影

📝shadow.component.html

html
<p>    shadow works!
+    <ng-content select=".head"></ng-content>
+    <ng-content select="[attr-content]"></ng-content>
+    <ng-content select="section"></ng-content>
+</p>
<p>    shadow works!
+    <ng-content select=".head"></ng-content>
+    <ng-content select="[attr-content]"></ng-content>
+    <ng-content select="section"></ng-content>
+</p>

📝app.component.html

html
<!-- 组件投影 -->
+<app-shadow>
+    <p class="head">头部投影内容</p>
+    <section>标签选择器投影内容</section>
+    <p attr-content>自定义属性选择器投影内容</p>
+</app-shadow>
<!-- 组件投影 -->
+<app-shadow>
+    <p class="head">头部投影内容</p>
+    <section>标签选择器投影内容</section>
+    <p attr-content>自定义属性选择器投影内容</p>
+</app-shadow>

🎖️结果展示

ViewChild

📝parent.component.ts

typescript
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+        export class ParentComponent implements OnInit,AfterViewInit {
+
+  // @ViewChild('box',{static:true}) private box:ElementRef //获取dom
+  // @ViewChild(ChildComponent,{static:true}) private instance:ChildComponent  //获取子组件方式一
+  @ViewChild('childcomponent',{static:true}) private childInstance:ChildComponent //获取子组件实例方式二
+
+  constructor() { //执行秩序(1)
+    // console.log('constructor',this.box);
+    // console.log('constructor',this.instance?.childdata);
+    // console.log('constructor',this.childInstance?.childdata);
+    console.log('constructor',this.childInstance);
+
+  }
+  ngOnInit(): void {//(2)
+    // console.log('ngOnInit',this.box.nativeElement);
+    // console.log('ngOnInit',this.instance.childdata);
+    console.log('ngOnInit',this.childInstance);
+    // console.log('ngOnInit',this.childInstance.childdata);
+
+  }
+  ngAfterViewInit(): void { //(3)在变更检测后执行,能保证获取到元素
+    //  console.log('ngAfterViewInit',this.box.nativeElement);
+    //  console.log('ngAfterViewInit',this.instance.childdata);
+     console.log('ngAfterViewInit',this.childInstance.childdata);
+
+  }
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+        export class ParentComponent implements OnInit,AfterViewInit {
+
+  // @ViewChild('box',{static:true}) private box:ElementRef //获取dom
+  // @ViewChild(ChildComponent,{static:true}) private instance:ChildComponent  //获取子组件方式一
+  @ViewChild('childcomponent',{static:true}) private childInstance:ChildComponent //获取子组件实例方式二
+
+  constructor() { //执行秩序(1)
+    // console.log('constructor',this.box);
+    // console.log('constructor',this.instance?.childdata);
+    // console.log('constructor',this.childInstance?.childdata);
+    console.log('constructor',this.childInstance);
+
+  }
+  ngOnInit(): void {//(2)
+    // console.log('ngOnInit',this.box.nativeElement);
+    // console.log('ngOnInit',this.instance.childdata);
+    console.log('ngOnInit',this.childInstance);
+    // console.log('ngOnInit',this.childInstance.childdata);
+
+  }
+  ngAfterViewInit(): void { //(3)在变更检测后执行,能保证获取到元素
+    //  console.log('ngAfterViewInit',this.box.nativeElement);
+    //  console.log('ngAfterViewInit',this.instance.childdata);
+     console.log('ngAfterViewInit',this.childInstance.childdata);
+
+  }

ViewChildren

📝parent.component.html

html
<!-- ViewChildren批量获取元素和组件 -->
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<app-child></app-child>
+<app-child></app-child>
+<app-child></app-child>
<!-- ViewChildren批量获取元素和组件 -->
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<div class="boxs" #boxs>mybox</div>
+<app-child></app-child>
+<app-child></app-child>
+<app-child></app-child>

📝parent.component.ts

typescript
import { AfterViewInit, Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+export class ParentComponent implements OnInit,AfterViewInit {
+
+  // ViewChildren批量获取元素和组件
+  @ViewChildren(ChildComponent) private childs:QueryList<ChildComponent>
+  @ViewChildren('boxs') private childs1:QueryList<ChildComponent>
+  constructor() { 
+  }
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void { //(3)
+     console.log(this.childs);
+     console.log(this.childs1);  //输出QueryList数组 
+      //QueryList中监听子组件变化的回调函数
+     this.childs1.changes.subscribe((changes)=>{
+       console.log(changes);
+
+      })
+  }
+}
import { AfterViewInit, Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
+import { ChildComponent } from './child/child.component';
+
+@Component({
+  selector: 'app-parent',
+  templateUrl: './parent.component.html',
+  styleUrls: ['./parent.component.css']
+})
+export class ParentComponent implements OnInit,AfterViewInit {
+
+  // ViewChildren批量获取元素和组件
+  @ViewChildren(ChildComponent) private childs:QueryList<ChildComponent>
+  @ViewChildren('boxs') private childs1:QueryList<ChildComponent>
+  constructor() { 
+  }
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void { //(3)
+     console.log(this.childs);
+     console.log(this.childs1);  //输出QueryList数组 
+      //QueryList中监听子组件变化的回调函数
+     this.childs1.changes.subscribe((changes)=>{
+       console.log(changes);
+
+      })
+  }
+}

ContentChild

获取投影中的dom元素、指令、组件

📝content-parent.html

html
<app-content-child>
+    <div class="head" #head>head</div>
+    <div class="main">main</div>
+    <div class="footer">footer</div>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+</app-content-child>
<app-content-child>
+    <div class="head" #head>head</div>
+    <div class="main">main</div>
+    <div class="footer">footer</div>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+</app-content-child>

📝content-child.html

html
<p>content-child works!</p>
+<ng-content></ng-content>
<p>content-child works!</p>
+<ng-content></ng-content>

📝content-child.ts

typescript
import { AfterViewInit, Component, ContentChild, ElementRef, OnInit } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+  @ContentChild('head',{static:true}) private head:ElementRef //获取投影中的dom元素
+  @ContentChild(ContentBoxComponent) private contentbox:ElementRef //获取组件
+  @ContentChild('cbox',{static:true}) private cbox:ElementRef // 有多个只会获取第一个
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.head);
+   console.log(this.contentbox);
+    console.log(this.cbox);
+
+  }
+}
import { AfterViewInit, Component, ContentChild, ElementRef, OnInit } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+  @ContentChild('head',{static:true}) private head:ElementRef //获取投影中的dom元素
+  @ContentChild(ContentBoxComponent) private contentbox:ElementRef //获取组件
+  @ContentChild('cbox',{static:true}) private cbox:ElementRef // 有多个只会获取第一个
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.head);
+   console.log(this.contentbox);
+    console.log(this.cbox);
+
+  }
+}

ContentChildren

用法类似ViewChildren, 批量获取投影中到组件或指令。

默认只批量获取直属组件,获取所有组件需开启:{ descendants: true }

📝content-parent.html

html
<p>content-parent works!</p>
+<app-content-child>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <div class="container">
+        <app-content-box #cbox></app-content-box>
+        <app-content-box #cbox></app-content-box>
+    </div>
+</app-content-child>
<p>content-parent works!</p>
+<app-content-child>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <app-content-box #cbox></app-content-box>
+    <div class="container">
+        <app-content-box #cbox></app-content-box>
+        <app-content-box #cbox></app-content-box>
+    </div>
+</app-content-child>

📝content-child.ts

typescript
import { AfterViewInit, Component,ContentChildren,OnInit, QueryList } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+    //ContentChildren没有{static:true}属性
+  @ContentChildren(ContentBoxComponent) private cboxs:QueryList<ContentBoxComponent>
+  @ContentChildren('cbox',{descendants: true}) private cboxss:QueryList<ContentBoxComponent>
+   constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.cboxs);//只获取直属投影组件
+    console.log(this.cboxss);//获取全部投影组件   
+  }
+}
import { AfterViewInit, Component,ContentChildren,OnInit, QueryList } from '@angular/core';
+import { ContentBoxComponent } from '../content-box/content-box.component';
+
+@Component({
+  selector: 'app-content-child',
+  templateUrl: './content-child.component.html',
+  styleUrls: ['./content-child.component.css']
+})
+export class ContentChildComponent implements OnInit,AfterViewInit {
+    //ContentChildren没有{static:true}属性
+  @ContentChildren(ContentBoxComponent) private cboxs:QueryList<ContentBoxComponent>
+  @ContentChildren('cbox',{descendants: true}) private cboxss:QueryList<ContentBoxComponent>
+   constructor() { }
+
+  ngOnInit(): void {
+  }
+  ngAfterViewInit(): void {
+    console.log(this.cboxs);//只获取直属投影组件
+    console.log(this.cboxss);//获取全部投影组件   
+  }
+}

自定义管道

typescript
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipepow'
+})
+export class PipepowPipe implements PipeTransform {
+
+  transform(value: number, exponent?: number): number {
+      //value:底数    exponent:指数
+    return Math.pow(value,isNaN(exponent) ? 1: exponent);
+  }
+}
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipepow'
+})
+export class PipepowPipe implements PipeTransform {
+
+  transform(value: number, exponent?: number): number {
+      //value:底数    exponent:指数
+    return Math.pow(value,isNaN(exponent) ? 1: exponent);
+  }
+}

在相应的Module中导入并使用

html
<div> {{8| pipepow}}</div>
+<div> {{8| pipepow:3}}</div>
+<div> {{value | pipepow:2}}</div>
+<div>Boost factor: <input [(ngModel)]="factor"></div>
+<div>Normal power: <input [(ngModel)]="power"></div>
+<div> {{factor | pipepow:power}}</div>
<div> {{8| pipepow}}</div>
+<div> {{8| pipepow:3}}</div>
+<div> {{value | pipepow:2}}</div>
+<div>Boost factor: <input [(ngModel)]="factor"></div>
+<div>Normal power: <input [(ngModel)]="power"></div>
+<div> {{factor | pipepow:power}}</div>

非纯管道

默认的管道都是纯的,Angular 会忽略复合对象中的变化,即管道只会检查原始值或对象引用

WARNING

可如果数组中的元素变化,增删改,由于引用没有变化,不会执行变更检测,所以不会执行管道的逻辑

Pipe2Pipe
typescript
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipe2',
+  pure: false //非纯管道开启方式一
+})
+export class Pipe2Pipe implements PipeTransform {
+
+  transform(allheros: any): any { //赛选会飞的英雄
+    return allheros.filter((item) => item.canFly);
+  }
+
+}
import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'pipe2',
+  pure: false //非纯管道开启方式一
+})
+export class Pipe2Pipe implements PipeTransform {
+
+  transform(allheros: any): any { //赛选会飞的英雄
+    return allheros.filter((item) => item.canFly);
+  }
+
+}
AppComponent
typescript
import { Component } from '@angular/core';
+interface Hero {
+  id: string;
+  name: string;
+  canFly?: boolean;
+}
+
+const HEROES = [
+              {
+                id: 'hero_0',
+                name: '盖伦',
+                canFly: false
+              },
+              {
+                id: 'hero_1',
+                name: '赵信',
+                canFly: false
+              },
+              {
+                id: 'hero_2',
+                name: '嘉文',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '易大师',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '泰达米尔',
+                canFly: true
+              }
+          ];
+@Component({
+  selector: 'app-root',
+  template: \`
+     <input type="text" #box (keyup.enter)="addHero(box.value)" placeholder="hero name" />
+     <button (click)="reset()">Reset</button>
+     <div *ngFor="let hero of (heroes | pipe2)">
+       {{hero.name}}
+     </div>
+  \`,
+})
+export class AppComponent {
+    heroes: Hero[] = [];
+     canFly = true;
+     constructor() {
+       this.reset();
+     }
+
+     ngOnInit(): void {
+     }
+     addHero(name: string) {
+       name = name.trim();
+       if (name) {
+         // 不改变引用没有用
+         this.heroes.push({ id: 'flier_' + Date.now(), name, canFly: this.canFly });
+        // 开启非纯管道方式二、改变引用,触发变更检测
+        // this.heroes = [...this.heroes,{id:'flier'+Date.now(),name,canFly:this.canFly}]
+       }
+     }
+
+   reset() { this.heroes = HEROES.slice(); }
+}
import { Component } from '@angular/core';
+interface Hero {
+  id: string;
+  name: string;
+  canFly?: boolean;
+}
+
+const HEROES = [
+              {
+                id: 'hero_0',
+                name: '盖伦',
+                canFly: false
+              },
+              {
+                id: 'hero_1',
+                name: '赵信',
+                canFly: false
+              },
+              {
+                id: 'hero_2',
+                name: '嘉文',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '易大师',
+                canFly: false
+              },
+              {
+                id: 'hero_3',
+                name: '泰达米尔',
+                canFly: true
+              }
+          ];
+@Component({
+  selector: 'app-root',
+  template: \`
+     <input type="text" #box (keyup.enter)="addHero(box.value)" placeholder="hero name" />
+     <button (click)="reset()">Reset</button>
+     <div *ngFor="let hero of (heroes | pipe2)">
+       {{hero.name}}
+     </div>
+  \`,
+})
+export class AppComponent {
+    heroes: Hero[] = [];
+     canFly = true;
+     constructor() {
+       this.reset();
+     }
+
+     ngOnInit(): void {
+     }
+     addHero(name: string) {
+       name = name.trim();
+       if (name) {
+         // 不改变引用没有用
+         this.heroes.push({ id: 'flier_' + Date.now(), name, canFly: this.canFly });
+        // 开启非纯管道方式二、改变引用,触发变更检测
+        // this.heroes = [...this.heroes,{id:'flier'+Date.now(),name,canFly:this.canFly}]
+       }
+     }
+
+   reset() { this.heroes = HEROES.slice(); }
+}

生命周期

生命周期函数:组件创建、组件更新、组件销毁的时候会触发的一系列的方法。

当 Angular 使用构造函数新建一个组件或指令后,就会按下面的顺序在特定时刻调用这些 生命周期钩子函数。

所有生命周期钩子函数执行顺序
typescript
import { AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, 
+        DoCheck, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit,OnChanges,DoCheck,AfterContentInit,
+        AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy{
+  constructor(){} //组件初始化,写简单的逻辑和数据初始化操作,(获取不到最新输入属性值)
+  ngOnChanges(changes: SimpleChanges): void {
+    console.log('changes ', changes); 
+      //可最早获取到输入属性最新值,输入属性更新时触发,但组件内部改变输入属性是不会触发的
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit '); //适合请求数据初始化组件,只调用一次
+  }
+  ngDoCheck(): void {
+    console.log('ngDoCheck ');
+  }
+
+  ngAfterContentInit(): void {
+      //在组件内容初始化之后调用,只调用一次。
+    console.log('ngAfterContentInit');
+  }
+
+  ngAfterContentChecked(): void {
+      //组件每次检查内容时调用
+    console.log('ngAfterContentChecked ');
+  }
+
+  ngAfterViewInit(): void {
+      //组件相应的视图初始化之后调用,只调用一次。
+    console.log('ngAfterViewInit ');
+  }
+
+  ngAfterViewChecked(): void {
+      //组件每次检查视图时调用
+    console.log('ngAfterViewChecked');
+
+  }
+
+  ngOnDestroy(): void {
+    //指令销毁前调用,适合理一些残存的状态操作:
+    //取消订阅可观察对象和 DOM 事件、停止 interval 计时器、
+    //反注册该指令在全局或应用服务中注册过的所有回调
+    console.log('ngOnDestroy');
+  }
+
+}
import { AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, 
+        DoCheck, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit,OnChanges,DoCheck,AfterContentInit,
+        AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy{
+  constructor(){} //组件初始化,写简单的逻辑和数据初始化操作,(获取不到最新输入属性值)
+  ngOnChanges(changes: SimpleChanges): void {
+    console.log('changes ', changes); 
+      //可最早获取到输入属性最新值,输入属性更新时触发,但组件内部改变输入属性是不会触发的
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit '); //适合请求数据初始化组件,只调用一次
+  }
+  ngDoCheck(): void {
+    console.log('ngDoCheck ');
+  }
+
+  ngAfterContentInit(): void {
+      //在组件内容初始化之后调用,只调用一次。
+    console.log('ngAfterContentInit');
+  }
+
+  ngAfterContentChecked(): void {
+      //组件每次检查内容时调用
+    console.log('ngAfterContentChecked ');
+  }
+
+  ngAfterViewInit(): void {
+      //组件相应的视图初始化之后调用,只调用一次。
+    console.log('ngAfterViewInit ');
+  }
+
+  ngAfterViewChecked(): void {
+      //组件每次检查视图时调用
+    console.log('ngAfterViewChecked');
+
+  }
+
+  ngOnDestroy(): void {
+    //指令销毁前调用,适合理一些残存的状态操作:
+    //取消订阅可观察对象和 DOM 事件、停止 interval 计时器、
+    //反注册该指令在全局或应用服务中注册过的所有回调
+    console.log('ngOnDestroy');
+  }
+
+}

当组件、父组件发生变更检测后都会调用这三个钩子:

模板中的DOM事件触发就会进行变更检测(<input (input)="$event">

ngDoCheck ngAfterContentChecked ngAfterViewChecked

  • 指令与组件共有的钩子
    • ngOnChanges
    • ngOnInit
    • ngDoCheck
    • ngOnDestroy
  • 组件特有的钩子
    • ngAfterContentInit
    • ngAfterContentChecked
    • ngAfterViewInit
    • ngAfterViewChecked

变更检测

默认策略下触发变更检测的时机

typescript
changeDetection:ChangeDetectionStrategy.Default
changeDetection:ChangeDetectionStrategy.Default
  • 事件:页面 click、submit、mouse down……
  • XHR:从后端服务器拿到数据
  • 定时器:setTimeout()、setInterval()

只要某个组件触发了以上中的一个,就会从顶级组件从上至下开始进行变更检测,每个组件都会进行变更检测,

检测组件中的值是否应该改变

注意

已经检测完的组件,不允许在被子组件修改,(子组件不能修改检测完的父组件数据),这就是单向数据流

onPush下触发变更检测时机

typescript
changeDetection:ChangeDetectionStrategy.OnPush
changeDetection:ChangeDetectionStrategy.OnPush

WARNING

onPush策略会把组件从组件树中剥离出去,他和他的子组件都不会检测了;

定时器会触发变更检测,但是依然会跳过onPush策略组件。

TIP

  • 组件的@Input引用发生变化。
  • 组件的 DOM 事件,包括它子组件的 DOM 事件,比如 click、submit、mouse down。
  • Observable 订阅事件,同时设置 Async pipe。
  • 手动调用:ChangeDetectorRef.detectChanges()、ChangeDetectorRef.markForCheck()、ApplicationRef.tick()方法
js
markForCheck() //把该视图显式标记为已更改(脏的),以便它下一轮再次进行检查。
+detectChanges() //检查该视图及其子视图。与 detach 结合使用可以实现局部变更检测。(强行检测)
markForCheck() //把该视图显式标记为已更改(脏的),以便它下一轮再次进行检查。
+detectChanges() //检查该视图及其子视图。与 detach 结合使用可以实现局部变更检测。(强行检测)

动态组件

如果说,之前在模版中调用的组件为静态组件(比如:app-xxx)

那么不用在模版里声明,而是通过ts动态插入到dom中到组件,可以视为动态组件

📝alert.component.ts:

typescript
import {Component, OnInit, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core';
+type AlertTheme = 'primary' | 'danger' | 'warning';
+
+export interface AlertOption {
+  content: string;
+  theme?: AlertTheme;
+}
+
+@Component({
+  selector: 'app-alert',
+  template: \`
+    <div [class]="wrapCls" role="alert">
+      <span class="content">{{ options.content }}</span>
+      <i class="close" (click)="closed.emit()">×</i>
+    </div>
+  \`,
+  styles: [\`
+    .close {
+      display: block;
+      width: 20px;
+      height: 20px;
+      position: absolute;
+      right: 10px;
+      top: 50%;
+      margin-top: -10px;
+      cursor: pointer;
+    }
+  \`],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AlertComponent implements OnInit {
+  options: Required<AlertOption> = {
+    content: '',
+    theme: 'primary'
+  }
+
+  @Output() closed = new EventEmitter<void>();
+  constructor() { }
+
+  ngOnInit(): void {}
+
+  get wrapCls(): string {
+    return 'alert alert-' + this.options.theme + ' fixed-top';
+  }
+
+  setOptions(options: AlertOption) {
+    this.options = { ...this.options, ...options };
+  }
+}
import {Component, OnInit, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core';
+type AlertTheme = 'primary' | 'danger' | 'warning';
+
+export interface AlertOption {
+  content: string;
+  theme?: AlertTheme;
+}
+
+@Component({
+  selector: 'app-alert',
+  template: \`
+    <div [class]="wrapCls" role="alert">
+      <span class="content">{{ options.content }}</span>
+      <i class="close" (click)="closed.emit()">×</i>
+    </div>
+  \`,
+  styles: [\`
+    .close {
+      display: block;
+      width: 20px;
+      height: 20px;
+      position: absolute;
+      right: 10px;
+      top: 50%;
+      margin-top: -10px;
+      cursor: pointer;
+    }
+  \`],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AlertComponent implements OnInit {
+  options: Required<AlertOption> = {
+    content: '',
+    theme: 'primary'
+  }
+
+  @Output() closed = new EventEmitter<void>();
+  constructor() { }
+
+  ngOnInit(): void {}
+
+  get wrapCls(): string {
+    return 'alert alert-' + this.options.theme + ' fixed-top';
+  }
+
+  setOptions(options: AlertOption) {
+    this.options = { ...this.options, ...options };
+  }
+}

调用 alert.component

typescript
import {ApplicationRef, Component, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector, OnInit} from '@angular/core';
+import {AlertComponent} from '../../components/alert/alert.component';
+
+@Component({
+  selector: 'app-show-data',
+  templateUrl: './show-data.component.html',
+  styleUrls: ['./show-data.component.scss']
+})
+export class ShowDataComponent implements OnInit {
+  private container: AlertComponent;
+  private componentRef: ComponentRef<AlertComponent>;
+  constructor(
+    private cfr: ComponentFactoryResolver,
+    private inject: Injector,
+    private appRef: ApplicationRef
+  ) {}
+
+  ngOnInit(): void {
+
+  }
+
+  showAlert() {
+    if (!this.container) {
+      this.container = this.getContainer();
+    }
+
+    // 调用组件的某个方法执行逻辑,比如下面这个传参
+    this.container.setOptions({ content: '一段提示', theme: 'warning' });
+  }
+
+  private getContainer(): AlertComponent {
+    // 创建指定类型的组件工厂(生产指定类型的组件)
+    const factory = this.cfr.resolveComponentFactory<AlertComponent>(AlertComponent);
+
+    // 根据指定的类型,创建组件的示例
+    this.componentRef = factory.create(this.inject);
+
+    // 将组件试图添加到试图树中,以激活变更检测
+    this.appRef.attachView(this.componentRef.hostView);
+
+    // 将组件到模版(包括app-alert标签),添加到body最后
+    document.body.appendChild((this.componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);
+
+    // 监听组件销毁事件
+    this.componentRef.onDestroy(() => {
+      console.log('componentRef destory');
+    });
+
+    // 获取组件实例,相当于用@ViewChild获取子组件一样
+    const { instance } = this.componentRef;
+
+    // 监听组件到output事件
+    instance.closed.subscribe(() => {
+      this.componentRef.destroy();
+      this.container = null;
+    });
+
+    return instance;
+  }
+}
import {ApplicationRef, Component, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector, OnInit} from '@angular/core';
+import {AlertComponent} from '../../components/alert/alert.component';
+
+@Component({
+  selector: 'app-show-data',
+  templateUrl: './show-data.component.html',
+  styleUrls: ['./show-data.component.scss']
+})
+export class ShowDataComponent implements OnInit {
+  private container: AlertComponent;
+  private componentRef: ComponentRef<AlertComponent>;
+  constructor(
+    private cfr: ComponentFactoryResolver,
+    private inject: Injector,
+    private appRef: ApplicationRef
+  ) {}
+
+  ngOnInit(): void {
+
+  }
+
+  showAlert() {
+    if (!this.container) {
+      this.container = this.getContainer();
+    }
+
+    // 调用组件的某个方法执行逻辑,比如下面这个传参
+    this.container.setOptions({ content: '一段提示', theme: 'warning' });
+  }
+
+  private getContainer(): AlertComponent {
+    // 创建指定类型的组件工厂(生产指定类型的组件)
+    const factory = this.cfr.resolveComponentFactory<AlertComponent>(AlertComponent);
+
+    // 根据指定的类型,创建组件的示例
+    this.componentRef = factory.create(this.inject);
+
+    // 将组件试图添加到试图树中,以激活变更检测
+    this.appRef.attachView(this.componentRef.hostView);
+
+    // 将组件到模版(包括app-alert标签),添加到body最后
+    document.body.appendChild((this.componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);
+
+    // 监听组件销毁事件
+    this.componentRef.onDestroy(() => {
+      console.log('componentRef destory');
+    });
+
+    // 获取组件实例,相当于用@ViewChild获取子组件一样
+    const { instance } = this.componentRef;
+
+    // 监听组件到output事件
+    instance.closed.subscribe(() => {
+      this.componentRef.destroy();
+      this.container = null;
+    });
+
+    return instance;
+  }
+}

v9和v10,动态组件都不需要entryComponents了,当然写了也没有问题 从v11开始,entryComponents可能被删除 v8及以前,动态组件一定要声明entryComponents

NgTemplateOutlet指令

NgTemplateOutlet是一个结构型指令

📝app.component.html

html
<app-tmp-outlet [render]="mycontent"></app-tmp-outlet>
+<ng-template #mycontent>
+    <div>一段父组件传入的内容</div>
+</ng-template>
+
+<!--使用tem-outlet组件中的数据-->
+<ng-template #mycontent let-context let-val="value">
+    <div>一段父组件传入的内容</div>
+    <div>使用outlet中的context:{{context}}</div>
+    <div>使用outlet中的value:{{val}}</div>
+</ng-template>
<app-tmp-outlet [render]="mycontent"></app-tmp-outlet>
+<ng-template #mycontent>
+    <div>一段父组件传入的内容</div>
+</ng-template>
+
+<!--使用tem-outlet组件中的数据-->
+<ng-template #mycontent let-context let-val="value">
+    <div>一段父组件传入的内容</div>
+    <div>使用outlet中的context:{{context}}</div>
+    <div>使用outlet中的value:{{val}}</div>
+</ng-template>

📝tmp-outlet.component.html

html
<p>tmp-outlet works!</p>
+<ng-container [ngTemplateOutlet]="render || default"></ng-container>
+
+<!--传递出去tem-outlet组件中的数据-->
+<ng-container [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-container>
+<!-- <ng-container *ngTemplateOutlet="render || default ;context:myContext"></ng-container>简写 -->
+
+<!--ng-template使用效果一样 -->
+<ng-template [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-template>
+<ng-template *ngTemplateOutlet="render || default ;context:myContext"></ng-template>
+<ng-template #default>
+    <div>一段组价默认的内容</div>
+</ng-template>
+
+<!-- context在内部ng-template也可以绑定 -->
+<ng-template #default let-context let-val="value">
+    <div>一段组价默认的内容</div>
+    <div> context:{{context}}</div>
+    <div> value:{{val}}</div>
+</ng-template>
<p>tmp-outlet works!</p>
+<ng-container [ngTemplateOutlet]="render || default"></ng-container>
+
+<!--传递出去tem-outlet组件中的数据-->
+<ng-container [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-container>
+<!-- <ng-container *ngTemplateOutlet="render || default ;context:myContext"></ng-container>简写 -->
+
+<!--ng-template使用效果一样 -->
+<ng-template [ngTemplateOutlet]="render || default" [ngTemplateOutletContext]="myContext"></ng-template>
+<ng-template *ngTemplateOutlet="render || default ;context:myContext"></ng-template>
+<ng-template #default>
+    <div>一段组价默认的内容</div>
+</ng-template>
+
+<!-- context在内部ng-template也可以绑定 -->
+<ng-template #default let-context let-val="value">
+    <div>一段组价默认的内容</div>
+    <div> context:{{context}}</div>
+    <div> value:{{val}}</div>
+</ng-template>

📝tmp-outlet.component.ts

typescript
import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-tmp-outlet',
+  templateUrl: './tmp-outlet.component.html',
+  styleUrls: ['./tmp-outlet.component.css']
+})
+export class TmpOutletComponent implements OnInit {
+
+  @Input()  render 
+  myContext = {$implicit: 'tmp-outlet组件里的context', value: 'tmp-outlet组件里的value'};
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-tmp-outlet',
+  templateUrl: './tmp-outlet.component.html',
+  styleUrls: ['./tmp-outlet.component.css']
+})
+export class TmpOutletComponent implements OnInit {
+
+  @Input()  render 
+  myContext = {$implicit: 'tmp-outlet组件里的context', value: 'tmp-outlet组件里的value'};
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
`,72),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.lean.js" "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.lean.js" new file mode 100644 index 00000000..d00510d1 --- /dev/null +++ "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md.574a1956.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Angular/Angular基础总结三.md","filePath":"Framework/Angular/Angular基础总结三.md"}'),p={name:"Framework/Angular/Angular基础总结三.md"},o=l("",72),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.js" "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.js" new file mode 100644 index 00000000..e8995044 --- /dev/null +++ "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.js" @@ -0,0 +1,753 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Angular/Angular基础总结二.md","filePath":"Framework/Angular/Angular基础总结二.md"}'),p={name:"Framework/Angular/Angular基础总结二.md"},o=l(`

双向绑定

1. 基本双向绑定

方法一:

📝父组件:

typescript
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: \`
+<app-sbind [size]="fontSizePx" (change)=" fontSizePx = $event"></app-sbind>
+
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>
+\`,
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: \`
+<app-sbind [size]="fontSizePx" (change)=" fontSizePx = $event"></app-sbind>
+
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>
+\`,
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}

📝子组件:

typescript
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  template: \`<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size">sbind 字体大小: {{size}}px</p>
+</div>\`,
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  @Output() change = new EventEmitter<number>();
+    
+  dec() {
+    this.change.emit(this.size-1)
+  }
+  inc() {
+    this.change.emit(this.size+1)
+  }
+    
+  constructor() { }
+  ngOnInit(): void {
+  }
+}
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  template: \`<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size">sbind 字体大小: {{size}}px</p>
+</div>\`,
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  @Output() change = new EventEmitter<number>();
+    
+  dec() {
+    this.change.emit(this.size-1)
+  }
+  inc() {
+    this.change.emit(this.size+1)
+  }
+    
+  constructor() { }
+  ngOnInit(): void {
+  }
+}

方法二:(联合写法)

📝父组件:app.component.html

html
<app-sbind [(size)]="fontSizePx"></app-sbind>
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>
<app-sbind [(size)]="fontSizePx"></app-sbind>
+<p [style.font-size.px]="fontSizePx">APP 字体大小: {{fontSizePx}}px</p>

📝父组件:app.component.ts

typescript
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}
import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-root',
+  template: './app.component.html',
+  styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+  fontSizePx = 16
+}

📝子组件:sbind.component.html

html
<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size"> sbind 字体大小: {{size}}px</p>
+</div>
<div>
+    <button (click)="dec()">-</button>
+    <button (click)="inc()">+</button>
+    <p [style.font-size.px]="size"> sbind 字体大小: {{size}}px</p>
+</div>

📝子组件:sbind.component.ts

typescript
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  templateUrl: './sbind.component.html',
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  // 双向绑定语法:output变量名=输入属性名+Change
+  @Output() sizeChange = new EventEmitter<number>();
+  constructor() { }
+
+  dec() {//减
+    this.sizeChange.emit(this.size-1)
+  }
+  inc() {//加
+    this.sizeChange.emit(this.size+1)
+  }
+  ngOnInit(): void {
+  }
+}
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-sbind',
+  templateUrl: './sbind.component.html',
+  styleUrls: ['./sbind.component.css']
+})
+export class SbindComponent implements OnInit {
+
+  //默认值
+  @Input()  size=16;
+  
+  // 双向绑定语法:output变量名=输入属性名+Change
+  @Output() sizeChange = new EventEmitter<number>();
+  constructor() { }
+
+  dec() {//减
+    this.sizeChange.emit(this.size-1)
+  }
+  inc() {//加
+    this.sizeChange.emit(this.size+1)
+  }
+  ngOnInit(): void {
+  }
+}

2. input双向绑定

普通写法:

typescript
<input type ="text" [value]="inputVal" (input)="inputVal = $event.target.value">
+<p>{{inputVal}}</p> //默认值 inputVal=''
<input type ="text" [value]="inputVal" (input)="inputVal = $event.target.value">
+<p>{{inputVal}}</p> //默认值 inputVal=''

简写形式:

WARNING

ngMoel 指令来源于FormsModule模块

[(ngMoel)]可拆解为:

  1. 名为ngModel的输入属性

  2. 名为ngModelChange的输出属性

html
<input type ="text" [(ngMoel)] ="inputVal">
+<p>{{inputVal}}</p> //默认值 inputVal=''
+<!-- <input type="text" [ngModel] = "inputVal" (ngModelChange) ="inputVal= $event">
+<p>{{inputVal}}</p> 完整写法-->
<input type ="text" [(ngMoel)] ="inputVal">
+<p>{{inputVal}}</p> //默认值 inputVal=''
+<!-- <input type="text" [ngModel] = "inputVal" (ngModelChange) ="inputVal= $event">
+<p>{{inputVal}}</p> 完整写法-->

3. 表单Form中双向绑定

TIP

表单中使用[(ngModel)],满足下列两个条件之一:

  • 给控件加上name属性
  • 将ngModelOptions.standalone设为true
html
 <form>
+    <input [(ngModel)]="value" name="name" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ name: 'name' }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ standalone: true }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{  name: 'name' ,standalone: true }" />
+  </form>
 <form>
+    <input [(ngModel)]="value" name="name" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ name: 'name' }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{ standalone: true }" />
+    <input [(ngModel)]="value" [ngModelOptions]="{  name: 'name' ,standalone: true }" />
+  </form>
ngModel拓展
typescript
@ViewChild(NgModel) private ngModel : NgModel;
+getVal(){
+    console.log(this.ngModel.viewModel)//获取[(ngModel)]所绑定input的值
+}
+setVal(){
+    this.ngModel.viewToModelUpdate( 'newValue')//赋值(不太好使)
+}
@ViewChild(NgModel) private ngModel : NgModel;
+getVal(){
+    console.log(this.ngModel.viewModel)//获取[(ngModel)]所绑定input的值
+}
+setVal(){
+    this.ngModel.viewToModelUpdate( 'newValue')//赋值(不太好使)
+}

属性型指令

指令:用于改变DOM元素的外观或行为的指令(组件是一种特殊的指令)

组件改为属性型指令

📝AppComponent

html
<div app-for>dasfsada</div>
<div app-for>dasfsada</div>
typescript
import {Component} from '@angular/core';
+@Component({
+  selector: '[app-decr]',//属性选择器
+  template: \`   
+  \`,
+})
+export class DecrComponent {
+  constructor() {}
+}
import {Component} from '@angular/core';
+@Component({
+  selector: '[app-decr]',//属性选择器
+  template: \`   
+  \`,
+})
+export class DecrComponent {
+  constructor() {}
+}

结构型指令

*ngIf指令

html
 <p *ngIf="isShow">一段文字 {{ isShow }}</p> 
+<!-- <p *ngIf="isShow as s">一段文字 {{ s }}</p> 局部变量:只能在标签内部使用-->
+isShow:true显示,反之(取决于绑定的值是否为真)
 <p *ngIf="isShow">一段文字 {{ isShow }}</p> 
+<!-- <p *ngIf="isShow as s">一段文字 {{ s }}</p> 局部变量:只能在标签内部使用-->
+isShow:true显示,反之(取决于绑定的值是否为真)

WARNING

会改变DOM结构,原理:移除和插入DOM节点

*ngIf 完整写法
html
 <ng-template [ngIf]="isShow" let-s>
+     <p *ngIf="isShow">一段文字 {{ isShow }} {{s}}</p> 
+ </ng-template>
 <ng-template [ngIf]="isShow" let-s>
+     <p *ngIf="isShow">一段文字 {{ isShow }} {{s}}</p> 
+ </ng-template>

ngIfElese

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: \`
+    <div *ngIf="condition; else elseBlock">condition为真时显示</div>
+
+    <ng-template ##elseBlock> 
+      <p> condition为假时显示 </p>
+    </ng-template>
+  \`,
+}) // ##elseBlock:模板的引用
+export class IfComp {
+  condition = true;
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: \`
+    <div *ngIf="condition; else elseBlock">condition为真时显示</div>
+
+    <ng-template ##elseBlock> 
+      <p> condition为假时显示 </p>
+    </ng-template>
+  \`,
+}) // ##elseBlock:模板的引用
+export class IfComp {
+  condition = true;
+}

ngIfThen

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: \`
+    <div *ngIf="condition; then thenBlock else elseBlock"></div>
+    <ng-template ##thenBlock> condition为true时显示</ng-template>
+    <ng-template ##elseBlock> condition为false时显示</ng-template>
+  \`,
+})//只会显示一个ng-template,第一个div只是用于承载,并不会显示
+export class IfComp {
+  condition = true;
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: \`
+    <div *ngIf="condition; then thenBlock else elseBlock"></div>
+    <ng-template ##thenBlock> condition为true时显示</ng-template>
+    <ng-template ##elseBlock> condition为false时显示</ng-template>
+  \`,
+})//只会显示一个ng-template,第一个div只是用于承载,并不会显示
+export class IfComp {
+  condition = true;
+}
TemplateRef拓展
typescript
import {Component, OnInit, ChangeDetectionStrategy, ViewChild, TemplateRef, AfterViewInit} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: \`
+    <button(click)="condition = !condition">toggle block</button>
+    <p *ngIf="condition else elseBlocks">{{ condition }} === true 时显示</p>
+    
+	<ng-template ##firstTpl>
+      <p>{{ condition }} === false 时显示</p>
+    </ng-template>
+  \`,
+})
+export class IfComponent implements OnInit, AfterViewInit {
+  elseBlocks: TemplateRef<any> = null; //获取组件的变量elseBlocks
+  @ViewChild('firstTpl', {static: true}) primaryBlock: TemplateRef<any> = null;
+  condition = false;
+  constructor() {
+
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit', this.primaryBlock);
+    this.elseBlocks = this.primaryBlock;
+   //获取到##firstTpl模板引用赋值给elseBlocks变量
+  }
+}
+//运行效果和ngIfElese案例一样
import {Component, OnInit, ChangeDetectionStrategy, ViewChild, TemplateRef, AfterViewInit} from '@angular/core';
+@Component({
+  selector: 'app-if',
+  template: \`
+    <button(click)="condition = !condition">toggle block</button>
+    <p *ngIf="condition else elseBlocks">{{ condition }} === true 时显示</p>
+    
+	<ng-template ##firstTpl>
+      <p>{{ condition }} === false 时显示</p>
+    </ng-template>
+  \`,
+})
+export class IfComponent implements OnInit, AfterViewInit {
+  elseBlocks: TemplateRef<any> = null; //获取组件的变量elseBlocks
+  @ViewChild('firstTpl', {static: true}) primaryBlock: TemplateRef<any> = null;
+  condition = false;
+  constructor() {
+
+  }
+  ngOnInit(): void {
+    console.log('ngOnInit', this.primaryBlock);
+    this.elseBlocks = this.primaryBlock;
+   //获取到##firstTpl模板引用赋值给elseBlocks变量
+  }
+}
+//运行效果和ngIfElese案例一样

*ngFor指令

typescript
import {Component} from '@angular/core';
+
+@Component({
+  selector: 'app-for',
+  template: \`
+    <ul>
+      <li *ngFor="let item of Persons; 
+			index as i; count as len; let ev = even; let od = odd; let f = first; let l = last;
+			trackBy: trackByPerson">{{ item.name }}</li>
+    </ul>
+  \`,
+})
+export class ForComponent {
+     Persons = [
+  {
+    id: 'p1',
+    name: '张三'
+  },
+    {
+    id: 'p2',
+    name: '李四'
+  },
+    {
+    id: 'p3',
+    name: '王五'
+  },
+  
+];
+trackByPerson(index,item){
+    return item.id	//追踪id,id值不变不刷新(提升性能)
+  }
+}
import {Component} from '@angular/core';
+
+@Component({
+  selector: 'app-for',
+  template: \`
+    <ul>
+      <li *ngFor="let item of Persons; 
+			index as i; count as len; let ev = even; let od = odd; let f = first; let l = last;
+			trackBy: trackByPerson">{{ item.name }}</li>
+    </ul>
+  \`,
+})
+export class ForComponent {
+     Persons = [
+  {
+    id: 'p1',
+    name: '张三'
+  },
+    {
+    id: 'p2',
+    name: '李四'
+  },
+    {
+    id: 'p3',
+    name: '王五'
+  },
+  
+];
+trackByPerson(index,item){
+    return item.id	//追踪id,id值不变不刷新(提升性能)
+  }
+}
ngFor局部变量
js
 index: number	//可迭代对象中当前条目的索引。
+ count: number	//可迭代对象的长度。
+ first: boolean	//如果当前条目是可迭代对象中的第一个条目则为 true。
+ last: boolean	//如果当前条目是可迭代对象中的最后一个条目则为 true。
+ even: boolean	//如果当前条目在可迭代对象中的索引号为偶数则为 true。
+ odd: boolean	//如果当前条目在可迭代对象中的索引号为奇数则为 true。
+ $implicit: T	//迭代目标(绑定到ngForOf)中每个条目的值。
+ ngForOf: NgIterable<T>	//迭代表达式的值。当表达式不局限于访问某个属性时,这会非常有用,比如在使用 async 管道时(userStreams | async)。
 index: number	//可迭代对象中当前条目的索引。
+ count: number	//可迭代对象的长度。
+ first: boolean	//如果当前条目是可迭代对象中的第一个条目则为 true。
+ last: boolean	//如果当前条目是可迭代对象中的最后一个条目则为 true。
+ even: boolean	//如果当前条目在可迭代对象中的索引号为偶数则为 true。
+ odd: boolean	//如果当前条目在可迭代对象中的索引号为奇数则为 true。
+ $implicit: T	//迭代目标(绑定到ngForOf)中每个条目的值。
+ ngForOf: NgIterable<T>	//迭代表达式的值。当表达式不局限于访问某个属性时,这会非常有用,比如在使用 async 管道时(userStreams | async)。
*ngFor展开写法
html
 <ul>
+     <ng-template
+       ngFor
+       [ngForOf]="heros"
+       [ngForTrackBy]="trackByHero"
+       let-item
+       let-i="index"
+       let-od="odd"
+       let-ev="even"
+       let-len="count"
+       let-f="first"
+       let-l="last">
+       <li [class.even]="ev" [class.odd]="od">
+         <p>index: {{ i }}</p>
+         <p>count: {{ len }}</p>
+         <p>name: {{ item.name }}</p>
+         <p>first: {{ f }} -- last: {{ l }}</p>
+         <hr>
+       </li>
+     </ng-template>
+   </ul>
 <ul>
+     <ng-template
+       ngFor
+       [ngForOf]="heros"
+       [ngForTrackBy]="trackByHero"
+       let-item
+       let-i="index"
+       let-od="odd"
+       let-ev="even"
+       let-len="count"
+       let-f="first"
+       let-l="last">
+       <li [class.even]="ev" [class.odd]="od">
+         <p>index: {{ i }}</p>
+         <p>count: {{ len }}</p>
+         <p>name: {{ item.name }}</p>
+         <p>first: {{ f }} -- last: {{ l }}</p>
+         <hr>
+       </li>
+     </ng-template>
+   </ul>

[ngSwitch]指令

WARNING

[ngSwitch] 为属性型指令

*ngSwitchCase为结构型指令

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-switch',
+  template: \`
+    <p>
+      <input type="radio" name="fruit" value="apple" id="apple" [(ngModel)]="fruit" />
+      <label for="apple">🍎</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="pear" id="pear" [(ngModel)]="fruit" />
+      <label for="pear">🍐</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="grape" id="grape" [(ngModel)]="fruit" />
+      <label for="grape">🍇</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="other" id="other" [(ngModel)]="fruit" />
+      <label for="other">other</label>
+    </p>
+    
+    selected fruit: {{ fruit }}
+    
+    <div class="content" [ngSwitch]="fruit">
+      <p *ngSwitchCase="'apple'">这是 苹果</p>
+      <p *ngSwitchCase="'pear'"> 这是 梨</p>
+      <p *ngSwitchCase="'grape'">这是 葡萄</p>
+      <p *ngSwitchDefault>啥都不是</p>
+    </div>
+  \`,
+})
+export class SwitchComponent {
+  fruit = '';
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-switch',
+  template: \`
+    <p>
+      <input type="radio" name="fruit" value="apple" id="apple" [(ngModel)]="fruit" />
+      <label for="apple">🍎</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="pear" id="pear" [(ngModel)]="fruit" />
+      <label for="pear">🍐</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="grape" id="grape" [(ngModel)]="fruit" />
+      <label for="grape">🍇</label>
+    </p>
+    <p>
+      <input type="radio" name="fruit" value="other" id="other" [(ngModel)]="fruit" />
+      <label for="other">other</label>
+    </p>
+    
+    selected fruit: {{ fruit }}
+    
+    <div class="content" [ngSwitch]="fruit">
+      <p *ngSwitchCase="'apple'">这是 苹果</p>
+      <p *ngSwitchCase="'pear'"> 这是 梨</p>
+      <p *ngSwitchCase="'grape'">这是 葡萄</p>
+      <p *ngSwitchDefault>啥都不是</p>
+    </div>
+  \`,
+})
+export class SwitchComponent {
+  fruit = '';
+}
[ngSwitch]展开写法
typescript
 <div class="content" [ngSwitch]="fruit">
+       <ng-template ngSwitchCase="apple">
+         <p>这是苹果</p>
+       </ng-template>
+       <ng-template ngSwitchCase="pear">
+         <p>这是梨</p>
+       </ng-template>
+       <ng-template ngSwitchCase="grape">
+         <p>这是葡萄</p>
+       </ng-template>
+       <ng-template ngSwitchDefault>
+         <p>啥都不是</p>
+       </ng-template>
+     </div>
 <div class="content" [ngSwitch]="fruit">
+       <ng-template ngSwitchCase="apple">
+         <p>这是苹果</p>
+       </ng-template>
+       <ng-template ngSwitchCase="pear">
+         <p>这是梨</p>
+       </ng-template>
+       <ng-template ngSwitchCase="grape">
+         <p>这是葡萄</p>
+       </ng-template>
+       <ng-template ngSwitchDefault>
+         <p>啥都不是</p>
+       </ng-template>
+     </div>

自定义指令

使用:

html
<p appHighlight highlightColor ='red'></p>
+<p appHighlight [highlightColor] ='color'></p>
+<p appHighlight='color'></p> <!-- 起别名后,输入属性和指令名设为一样-->
<p appHighlight highlightColor ='red'></p>
+<p appHighlight [highlightColor] ='color'></p>
+<p appHighlight='color'></p> <!-- 起别名后,输入属性和指令名设为一样-->

自定义高亮指令(属性型)

typescript
import {Directive, ElementRef, EventEmitter, HostListener, Input, Output} from '@angular/core';
+
+@Directive({
+  selector: '[appHighlight]'
+})
+export class HighlightDirective {
+  @Input() highlightColor: string;
+ // @Input('appHighlight') highlightColor: string;起别名
+  @Output() colorChange = new EventEmitter<string>();
+    //1.获取dom
+  constructor(private el: ElementRef) {
+    console.log('appHighlight');
+  }
+   
+  @HostListener('mouseenter') onMouseEnter() {
+    this.highlight(this.highlightColor || 'yellow');
+  }
+	//内部事件监听
+  @HostListener('mouseleave',['$event']) onMouseLeave() {
+    this.highlight('');
+      console.log(event)	//传递事件对象
+  }
+
+  private highlight(color: string) {
+      //2.操作dom (操作dom备用选择)
+    this.el.nativeElement.style.backgroundColor = color;
+    this.colorChange.emit(color);
+  }
+}
import {Directive, ElementRef, EventEmitter, HostListener, Input, Output} from '@angular/core';
+
+@Directive({
+  selector: '[appHighlight]'
+})
+export class HighlightDirective {
+  @Input() highlightColor: string;
+ // @Input('appHighlight') highlightColor: string;起别名
+  @Output() colorChange = new EventEmitter<string>();
+    //1.获取dom
+  constructor(private el: ElementRef) {
+    console.log('appHighlight');
+  }
+   
+  @HostListener('mouseenter') onMouseEnter() {
+    this.highlight(this.highlightColor || 'yellow');
+  }
+	//内部事件监听
+  @HostListener('mouseleave',['$event']) onMouseLeave() {
+    this.highlight('');
+      console.log(event)	//传递事件对象
+  }
+
+  private highlight(color: string) {
+      //2.操作dom (操作dom备用选择)
+    this.el.nativeElement.style.backgroundColor = color;
+    this.colorChange.emit(color);
+  }
+}

相对于原生事件监听 addEventListener()  的优点 :

  1. 会自动销毁,不会导致内存泄漏

  2. 不用必须确保每个DOM API都能用

自定义unless指令(结构型)

定义
typescript
import {Directive, Input, OnChanges, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
+export class UnlessContext<T = unknown> {
+  $implicit: T = null;
+  appUnless: T = null;
+  attr: T = null;
+}
+@Directive({
+  selector: '[appUnless]'
+})
+export class UnlessDirective implements OnChanges {
+  @Input('appUnless') unless: boolean;
+  private hasView = false;//是否已显示
+  private context = new UnlessContext();
+  
+  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {
+    // console.log(this.templateRef);
+    // console.log(this.viewContainer);
+  }
+	//监听输入属性变化
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes['unless']) {
+    this.context.$implicit = this.context.appUnless = this.unless;
+    this.context.attr = 'aaab';
+      if (this.unless) {
+        if (this.hasView) {
+          this.viewContainer.clear();
+          this.hasView = false;
+        }
+      } else {
+        if (!this.hasView) {
+          // 这里使用的构造提供的模版(this.templateRef)
+          // 实战中可以通过一个input属性传入模版
+          this.viewContainer.createEmbeddedView(this.templateRef, this.context);
+          this.hasView = true;
+        }
+      }
+    }
+  }
+}
import {Directive, Input, OnChanges, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
+export class UnlessContext<T = unknown> {
+  $implicit: T = null;
+  appUnless: T = null;
+  attr: T = null;
+}
+@Directive({
+  selector: '[appUnless]'
+})
+export class UnlessDirective implements OnChanges {
+  @Input('appUnless') unless: boolean;
+  private hasView = false;//是否已显示
+  private context = new UnlessContext();
+  
+  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {
+    // console.log(this.templateRef);
+    // console.log(this.viewContainer);
+  }
+	//监听输入属性变化
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes['unless']) {
+    this.context.$implicit = this.context.appUnless = this.unless;
+    this.context.attr = 'aaab';
+      if (this.unless) {
+        if (this.hasView) {
+          this.viewContainer.clear();
+          this.hasView = false;
+        }
+      } else {
+        if (!this.hasView) {
+          // 这里使用的构造提供的模版(this.templateRef)
+          // 实战中可以通过一个input属性传入模版
+          this.viewContainer.createEmbeddedView(this.templateRef, this.context);
+          this.hasView = true;
+        }
+      }
+    }
+  }
+}
调用
typescript
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+     <section>
+       <h3>unless</h3>
+       <button  (click)="showUnless = !showUnless">toggle unless {{ showUnless }}</button>
+       <p *appUnless="showUnless">测试unless driective -- {{ showUnless }}</p>
+       <p *appUnless="showUnless as un">测试unless driective alias un -- {{ un }}</p>
+       <p *appUnless="showUnless; let un; let attr=attr;">别名:  {{ un }} attr: {{ attr }}</p>
+     </section>
+  \`,
+})
+export class AppComponent {
+  show = false;	//false: 显示 	true: 隐藏
+}
import { Component } from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+     <section>
+       <h3>unless</h3>
+       <button  (click)="showUnless = !showUnless">toggle unless {{ showUnless }}</button>
+       <p *appUnless="showUnless">测试unless driective -- {{ showUnless }}</p>
+       <p *appUnless="showUnless as un">测试unless driective alias un -- {{ un }}</p>
+       <p *appUnless="showUnless; let un; let attr=attr;">别名:  {{ un }} attr: {{ attr }}</p>
+     </section>
+  \`,
+})
+export class AppComponent {
+  show = false;	//false: 显示 	true: 隐藏
+}

模板元素

ng-template

html
<ng-template>是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。
+事实上,在渲染视图之前,Angular 会把 <ng-template> 及其内容替换为一个注释。
<ng-template>是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。
+事实上,在渲染视图之前,Angular 会把 <ng-template> 及其内容替换为一个注释。

WARNING

没有使用结构型指令,ng-template中的元素是不可见的

ng-container

html
Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。
+<ng-container> 是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScript 中 if 块中的花括号。
Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。
+<ng-container> 是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScript 中 if 块中的花括号。
js
if (someCondition) {
+  statement1;
+  statement2;
+  statement3;
+}
if (someCondition) {
+  statement1;
+  statement2;
+  statement3;
+}

模板引用变量

使用井号(##)声明模板引用变量,可以获取DOM 元素、指令、组件、TemplateRef 或 Web Component。

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-tpl-var',
+  template: \`
+    <input ##phone placeholder="phone number" />
+ 	<input ref-phone placeholder="phone number" />
+    <button (click)="callPhone(phone.value)">Call</button>
+  \`,
+})	//两种写法
+export class TplVarComponent {
+  constructor() { }
+  callPhone(value: string) {
+    console.log('callPhone', value);
+  }
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-tpl-var',
+  template: \`
+    <input ##phone placeholder="phone number" />
+ 	<input ref-phone placeholder="phone number" />
+    <button (click)="callPhone(phone.value)">Call</button>
+  \`,
+})	//两种写法
+export class TplVarComponent {
+  constructor() { }
+  callPhone(value: string) {
+    console.log('callPhone', value);
+  }
+}

在外部获取组件引用,绑定组件内方法

typescript
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+    
+      <button (click)="sizer.inc()">app inc</button>
+      <app-sbind [(size)]="size" ##sizer></app-sbind>
+      size: {{ size }}
+    
+  \`,
+})
+export class AppComponent {
+  size = 16;
+  constructor() { }
+}
import {Component} from '@angular/core';
+@Component({
+  selector: 'app-root',
+  template: \`
+    
+      <button (click)="sizer.inc()">app inc</button>
+      <app-sbind [(size)]="size" ##sizer></app-sbind>
+      size: {{ size }}
+    
+  \`,
+})
+export class AppComponent {
+  size = 16;
+  constructor() { }
+}

操作符

管道 |

WARNING

模板变量可以通过一条或多条管道格式化数据,

默认的管道都是纯的,Angular 会忽略复合对象中的变化,即管道只会检查原始值或对象引用,

如果数组中的元素变化,增删改,引用没有变化,而不会执行管道的逻辑。

管道名称作用
DatePipe格式化日期
DecimalPipe数字转字符串,并可以指定格式
KeyValuePipe使ngFor可以循环Object或Map对象
JsonPipe将值转成json格式
TitleCasePipe把首字母大写,其它小写
SlicePipe截取Array或String
PercentPipe数字转百分比
LowerCasePipe转化为小写
UpperCasePipe转化为大写
AsyncPipe自动订阅模板中的Observable或Promise

安全链?

用于可能为空的引用需要使用时,对null、undefined进行保护,保证数据请求前能正常渲染模板

html
<p>{{person?.name}}</p>
<p>{{person?.name}}</p>

非空断言!

DANGER

在ts中,开启--strictNullChecks后,将一个可能是undefined或null的变量赋给一个有确切类型的变量时,会报错。在特定情况下,我们断定变量一定不是undefined或null,就可以使用非空断言操作符。

使用非空断言的两个步骤:

tsconfig.json中设置"strictNullChecks": true

tslint.json中设置 "no-non-null-assertion": false

类型转换函数$any()

绑定的表达式不能或很难指定类型时使用

假设无法确定item的类型,也就不能确定item是否有bestByDate,这时就会报错。

可以用$any()把item视为any类型,避免其报错(也可以用这个函数绑定组件中不存在的变量)

typescript
<p> {{$any(item).bestByDate}}</p>
<p> {{$any(item).bestByDate}}</p>
`,83),e=[o];function t(c,r,y,i,D,A){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.lean.js" "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.lean.js" new file mode 100644 index 00000000..63feae82 --- /dev/null +++ "b/assets/Framework_Angular_Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md.0a8462a7.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Angular/Angular基础总结二.md","filePath":"Framework/Angular/Angular基础总结二.md"}'),p={name:"Framework/Angular/Angular基础总结二.md"},o=l("",83),e=[o];function t(c,r,y,i,D,A){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.js" "b/assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.js" new file mode 100644 index 00000000..5755109f --- /dev/null +++ "b/assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.js" @@ -0,0 +1,436 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/React/React基础总结一.md","filePath":"Framework/React/React基础总结一.md"}'),l={name:"Framework/React/React基础总结一.md"},o=p(`

一、前置知识

虚拟DOM

jsx
const VDOM = (  /* 此处一定不要写引号,因为不是字符串 */
+			<h1 id="title">
+				<span>Hello,React</span>
+			</h1>
+		)
+//2.渲染虚拟DOM到页面   准备好一个“容器”<div id="root"></div> 
+ReactDOM.render(VDOM,document.getElementById('root'))
const VDOM = (  /* 此处一定不要写引号,因为不是字符串 */
+			<h1 id="title">
+				<span>Hello,React</span>
+			</h1>
+		)
+//2.渲染虚拟DOM到页面   准备好一个“容器”<div id="root"></div> 
+ReactDOM.render(VDOM,document.getElementById('root'))

关于虚拟DOM:

1.本质是Object类型的对象(一般对象)

​ 2.虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。

​ 3.虚拟DOM最终会被React转化为真实DOM,呈现在页面上

JSX语法规则

​ 1.定义虚拟DOM时,不要写引号。

​ 2.标签中混入JS表达式时要用 {}

​ 3.样式的类名指定不要用class,要用className。

​ 4.只有一个根标签

​ 5.标签必须闭合

​ 6.标签首字母

注意

一定注意区分:【js语句(代码)】与【js表达式】

1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方

 (1). a
+      (2). a+b
+      (3). demo(1)
+      (4). arr.map() 
+      (5). function test () {}
+

2.语句(代码):

js
(1).if(){}
+(2).for(){}
+(3).switch(){case:xxxx}
(1).if(){}
+(2).for(){}
+(3).switch(){case:xxxx}

二、组件

函数式组件

js
	<!-- 准备好一个容器-->
+	<div id="root"></div>
+	
+	<!-- 引入react核心库 -->
+	<script type="text/javascript" src="../js/react.development.js"></script>
+	<!-- 引入react-dom用于支持react操作DOM -->
+	<script type="text/javascript" src="../js/react-dom.development.js"></script>
+	<!-- 引入babel用于将jsx转为js -->
+	<script type="text/javascript" src="../js/babel.min.js"></script>
+
+	<script type="text/babel">
+		//1.创建函数式组件
+		function MyComponent(){
+			console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
+			return <h2>函数式组件</h2>
+		}
+		//2.渲染组件到页面
+		ReactDOM.render(<MyComponent/>,document.getElementById('root'))
+		/* 
+			执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
+					1.React解析组件标签,找到了MyComponent组件。
+					2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
+		*/
+	</script>
	<!-- 准备好一个容器-->
+	<div id="root"></div>
+	
+	<!-- 引入react核心库 -->
+	<script type="text/javascript" src="../js/react.development.js"></script>
+	<!-- 引入react-dom用于支持react操作DOM -->
+	<script type="text/javascript" src="../js/react-dom.development.js"></script>
+	<!-- 引入babel用于将jsx转为js -->
+	<script type="text/javascript" src="../js/babel.min.js"></script>
+
+	<script type="text/babel">
+		//1.创建函数式组件
+		function MyComponent(){
+			console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
+			return <h2>函数式组件</h2>
+		}
+		//2.渲染组件到页面
+		ReactDOM.render(<MyComponent/>,document.getElementById('root'))
+		/* 
+			执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
+					1.React解析组件标签,找到了MyComponent组件。
+					2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
+		*/
+	</script>

类式组件

js
//创建类式组件
+class MyComponent extends React.Component {
+	render(){
+		//render在MyComponent的原型对象上,供实例使用。
+		//render中的this指向MyComponent组件实例对象。
+		console.log('render中的this:',this);
+		return <h2>类式组件</h2>
+	}
+}
+//渲染组件到页面
+ReactDOM.render(<MyComponent/>,document.getElementById('root'))
//创建类式组件
+class MyComponent extends React.Component {
+	render(){
+		//render在MyComponent的原型对象上,供实例使用。
+		//render中的this指向MyComponent组件实例对象。
+		console.log('render中的this:',this);
+		return <h2>类式组件</h2>
+	}
+}
+//渲染组件到页面
+ReactDOM.render(<MyComponent/>,document.getElementById('root'))

TIP

执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?

​ 1.React解析组件标签,找到了MyComponent组件。

​ 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。

​ 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。

补充

受控组件:React 中受控组件的是指表单元素的控制是交给 React ,表单元素的值是完全交由组件的 state 控制。

​ 受控组件也可以用于描述内部状态由传入 props 控制的 React 自定义组件。

非受控组件: 表单元素的状态并不受 React 组件状态的影响,表单元素的值存储于 DOM 元素中。

​ 如果要 React 组件要获取 DOM 元素的值,需要通过绑定 ref 的方式去获取。

组实例三大属性

state

jsx
//1.创建组件
+class Weather extends React.Component{
+	//初始化状态
+	state = {isHot:false,wind:'微风'}
+	render(){
+		const {isHot,wind} = this.state
+		return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}{wind}</h1>
+	}
+	//自定义方法————要用赋值语句的形式+箭头函数 **
+	changeWeather = () =>{
+		const isHot = this.state.isHot
+		this.setState({isHot:!isHot})
+	}
+}
+//2.渲染组件到页面
+ReactDOM.render(<Weather/>,document.getElementById('test'))
//1.创建组件
+class Weather extends React.Component{
+	//初始化状态
+	state = {isHot:false,wind:'微风'}
+	render(){
+		const {isHot,wind} = this.state
+		return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}{wind}</h1>
+	}
+	//自定义方法————要用赋值语句的形式+箭头函数 **
+	changeWeather = () =>{
+		const isHot = this.state.isHot
+		this.setState({isHot:!isHot})
+	}
+}
+//2.渲染组件到页面
+ReactDOM.render(<Weather/>,document.getElementById('test'))

props

jsx
//创建组件
+class Person extends React.Component{
+    //props简写形式: 对标签属性进行类型、必要性的限制
+    static propTypes = {
+        name:PropTypes.string.isRequired, //限制name必传,且为字符串
+        sex:PropTypes.string,//限制sex为字符串
+        age:PropTypes.number,//限制age为数值
+	}
+	render(){
+		const {name,age,sex} = this.props
+		return (
+			<ul>
+				<li>姓名:{name}</li>
+				<li>性别:{sex}</li>
+				<li>年龄:{age+1}</li>
+			</ul>
+		)
+	}
+}
+ 
+/*Person.propTypes = {
+	name:PropTypes.string.isRequired, //限制name必传,且为字符串
+	sex:PropTypes.string,//限制sex为字符串
+	age:PropTypes.number,//限制age为数值
+	speak:PropTypes.func,//限制speak为函数
+}
+
+Person.defaultProps = {//指定默认标签属性值
+	sex:'男',//sex默认值为男
+	age:18 //age默认值为18
+}*/
+//渲染组件到页面
+ReactDOM.render(<Person name="jerry" age={19}  sex=""/>,document.getElementById('test1'))
+ReactDOM.render(<Person name="tom" age={18} sex=""/>,document.getElementById('test2'))
+
+const p = {name:'老刘',age:18,sex:''}
+// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
+ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
//创建组件
+class Person extends React.Component{
+    //props简写形式: 对标签属性进行类型、必要性的限制
+    static propTypes = {
+        name:PropTypes.string.isRequired, //限制name必传,且为字符串
+        sex:PropTypes.string,//限制sex为字符串
+        age:PropTypes.number,//限制age为数值
+	}
+	render(){
+		const {name,age,sex} = this.props
+		return (
+			<ul>
+				<li>姓名:{name}</li>
+				<li>性别:{sex}</li>
+				<li>年龄:{age+1}</li>
+			</ul>
+		)
+	}
+}
+ 
+/*Person.propTypes = {
+	name:PropTypes.string.isRequired, //限制name必传,且为字符串
+	sex:PropTypes.string,//限制sex为字符串
+	age:PropTypes.number,//限制age为数值
+	speak:PropTypes.func,//限制speak为函数
+}
+
+Person.defaultProps = {//指定默认标签属性值
+	sex:'男',//sex默认值为男
+	age:18 //age默认值为18
+}*/
+//渲染组件到页面
+ReactDOM.render(<Person name="jerry" age={19}  sex=""/>,document.getElementById('test1'))
+ReactDOM.render(<Person name="tom" age={18} sex=""/>,document.getElementById('test2'))
+
+const p = {name:'老刘',age:18,sex:''}
+// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
+ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))

函数组件使用props

jsx
function Person (props){
+	const {name,age,sex} = props
+	return (
+        <ul>
+            <li>姓名:{name}</li>
+            <li>性别:{sex}</li>
+            <li>年龄:{age}</li>
+        </ul>
+	)
+}
+Person.propTypes = {
+	name:PropTypes.string.isRequired, 
+	sex:PropTypes.string,
+	age:PropTypes.number,
+}
+
+Person.defaultProps = {
+	sex:'',
+	age:18 
+}
function Person (props){
+	const {name,age,sex} = props
+	return (
+        <ul>
+            <li>姓名:{name}</li>
+            <li>性别:{sex}</li>
+            <li>年龄:{age}</li>
+        </ul>
+	)
+}
+Person.propTypes = {
+	name:PropTypes.string.isRequired, 
+	sex:PropTypes.string,
+	age:PropTypes.number,
+}
+
+Person.defaultProps = {
+	sex:'',
+	age:18 
+}

refs

jsx
class Demo extends React.Component{
+    myRef2 = React.createRef() //3.createRef形式
+    //React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
+    
+	showData = ()=>{
+		const {input1} = this.refs //1.字符串形式
+        const {input2} = this //2.回调函数形式
+	}
+    saveInput = (c)=>{
+        this.input2 = c;
+        console.log('=@=',c);
+    }
+	render(){
+		return(
+			<div>
+				<input ref="input1" type="text"/> {/*字符串形式*/}
+			  	<input ref={(c)=>{this.input2 = c;console.log('@',c);}} type="text"/> {/*回调函数形式*/}
+               	<input ref={this.saveInput} type="text"/>
+                <input ref={this.myRef} type="text" />{/*createRef形式*/}
+			</div>
+		)
+	}
+}
+ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))
class Demo extends React.Component{
+    myRef2 = React.createRef() //3.createRef形式
+    //React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
+    
+	showData = ()=>{
+		const {input1} = this.refs //1.字符串形式
+        const {input2} = this //2.回调函数形式
+	}
+    saveInput = (c)=>{
+        this.input2 = c;
+        console.log('=@=',c);
+    }
+	render(){
+		return(
+			<div>
+				<input ref="input1" type="text"/> {/*字符串形式*/}
+			  	<input ref={(c)=>{this.input2 = c;console.log('@',c);}} type="text"/> {/*回调函数形式*/}
+               	<input ref={this.saveInput} type="text"/>
+                <input ref={this.myRef} type="text" />{/*createRef形式*/}
+			</div>
+		)
+	}
+}
+ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))

注意: 回调函数形式执行次数

事件处理

WARNING

(1).通过onXxx属性指定事件处理函数(注意大小写)

​ a. React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性

​ b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效

(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref

高阶函数:参数或返回值是一个函数满足一个条件则为高阶函数。

​ 常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

js
function sum(a){
+	return(b)=>{
+		return (c)=>{
+			return a+b+c
+		}
+	}
+}
+//函数柯里化传参
+saveFormData = (dataType)=>{
+	return (event)=>{
+		this.setState({[dataType]:event.target.value})
+	}
+}
+//<input onChange={this.saveFormData('username')} type="text" name="username"/>
+
+//箭头函数传参
+saveFormData = (dataType,event)=>{
+        this.setState({[dataType]:event.target.value})
+    }
+//<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
function sum(a){
+	return(b)=>{
+		return (c)=>{
+			return a+b+c
+		}
+	}
+}
+//函数柯里化传参
+saveFormData = (dataType)=>{
+	return (event)=>{
+		this.setState({[dataType]:event.target.value})
+	}
+}
+//<input onChange={this.saveFormData('username')} type="text" name="username"/>
+
+//箭头函数传参
+saveFormData = (dataType,event)=>{
+        this.setState({[dataType]:event.target.value})
+    }
+//<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>

组件生命周期

旧版(16)

image-20220421223156627

js
/* 
+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	componentWillMount()
+            3.	render()
+            4.	componentDidMount() =====> 常用
+            一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+            
+2. 更新阶段: 由组件内部this.setSate()或父组件render触发
+            1.	shouldComponentUpdate()
+            2.	componentWillUpdate()
+            3.	render() =====> 必须使用的一个
+            4.	componentDidUpdate()
+            
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+            一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
+*/
/* 
+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	componentWillMount()
+            3.	render()
+            4.	componentDidMount() =====> 常用
+            一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+            
+2. 更新阶段: 由组件内部this.setSate()或父组件render触发
+            1.	shouldComponentUpdate()
+            2.	componentWillUpdate()
+            3.	render() =====> 必须使用的一个
+            4.	componentDidUpdate()
+            
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+            一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
+*/

新版(17+)

image-20220421223604701

markdown

+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	getDerivedStateFromProps
+            3.	render()
+            4.	componentDidMount() =====> 常用
+                        一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
+            1.	getDerivedStateFromProps
+            2.	shouldComponentUpdate()
+            3.	render()
+            4.	getSnapshotBeforeUpdate
+            5.	componentDidUpdate()
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+                        一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

+1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
+            1.	constructor()
+            2.	getDerivedStateFromProps
+            3.	render()
+            4.	componentDidMount() =====> 常用
+                        一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
+2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
+            1.	getDerivedStateFromProps
+            2.	shouldComponentUpdate()
+            3.	render()
+            4.	getSnapshotBeforeUpdate
+            5.	componentDidUpdate()
+3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
+            1.	componentWillUnmount()  =====> 常用
+                        一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

getSnapshotBeforeUpdate

在render之前调用,state已更新

典型场景:获取render之前的dom状态

getDerivedStateFromProps

TIP

1:当state需要从props初始化时,使用

2:尽量不使用,维护俩者状态需要消耗额外资源,增加复杂度

3:每次render都会调用

4:典型场景表单获取默认值

markdown
 面试相关题:
+	1). react/vue中的key有什么作用?(key的内部原理是什么?)
+	2). 为什么遍历列表时,key最好不要用index?
+
+1. 虚拟DOM中key的作用:
+	1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
+
+	2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 
+                    随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
+
+        a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
+                    (1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
+                    (2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
+
+        b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
+                    根据数据创建新的真实DOM,随后渲染到到页面
+
+2. 用index作为key可能会引发的问题:
+    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
+                    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
+
+    2. 如果结构中还包含输入类的DOM:
+                    会产生错误DOM更新 ==> 界面有问题。
+
+    3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
+        仅用于渲染列表用于展示,使用index作为key是没有问题的。
+
+3. 开发中如何选择key?:
+    1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
+    2.如果确定只是简单的展示数据,用index也是可以的。
 面试相关题:
+	1). react/vue中的key有什么作用?(key的内部原理是什么?)
+	2). 为什么遍历列表时,key最好不要用index?
+
+1. 虚拟DOM中key的作用:
+	1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
+
+	2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 
+                    随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
+
+        a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
+                    (1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
+                    (2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
+
+        b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
+                    根据数据创建新的真实DOM,随后渲染到到页面
+
+2. 用index作为key可能会引发的问题:
+    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
+                    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
+
+    2. 如果结构中还包含输入类的DOM:
+                    会产生错误DOM更新 ==> 界面有问题。
+
+    3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
+        仅用于渲染列表用于展示,使用index作为key是没有问题的。
+
+3. 开发中如何选择key?:
+    1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
+    2.如果确定只是简单的展示数据,用index也是可以的。
`,59),e=[o];function t(c,r,y,D,A,i){return n(),a("div",null,e)}const C=s(l,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.lean.js" "b/assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.lean.js" new file mode 100644 index 00000000..f14e0c19 --- /dev/null +++ "b/assets/Framework_React_React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md.fc5d41af.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/React/React基础总结一.md","filePath":"Framework/React/React基础总结一.md"}'),l={name:"Framework/React/React基础总结一.md"},o=p("",59),e=[o];function t(c,r,y,D,A,i){return n(),a("div",null,e)}const C=s(l,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.js" "b/assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.js" new file mode 100644 index 00000000..01ce1a44 --- /dev/null +++ "b/assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.js" @@ -0,0 +1 @@ +import{_ as a,o as l,c as i,k as e,a as t}from"./chunks/framework.c53372a0.js";const k=JSON.parse('{"title":"Vite底层原理学习","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/Vite原理学习.md","filePath":"Framework/Vue/Vite原理学习.md"}'),s={name:"Framework/Vue/Vite原理学习.md"},o=e("h1",{id:"vite底层原理学习",tabindex:"-1"},[t("Vite底层原理学习 "),e("a",{class:"header-anchor",href:"#vite底层原理学习","aria-label":'Permalink to "Vite底层原理学习"'},"​")],-1),r=e("h2",{id:"构建工具承担",tabindex:"-1"},[t("构建工具承担: "),e("a",{class:"header-anchor",href:"#构建工具承担","aria-label":'Permalink to "构建工具承担:"'},"​")],-1),n=e("ol",null,[e("li",null,"模块化开发支持:ES Module、CommonJS、AMD、CMD等"),e("li",null,"处理代码兼容性:babel语法降级,less/sass/stylus等语法转换"),e("li",null,"提升项目性能:压缩代码,合并代码,图片压缩,代码分割,懒加载,预加载等"),e("li",null,"优化开发体验:热更新,自动刷新,代理服务器,自动打开浏览器等"),e("li",null,"统一开发标准:eslint代码检查,prettier代码格式化,git提交规范等")],-1),c=[o,r,n];function d(_,h,m,u,p,V){return l(),i("div",null,c)}const b=a(s,[["render",d]]);export{k as __pageData,b as default}; diff --git "a/assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.lean.js" "b/assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.lean.js" new file mode 100644 index 00000000..01ce1a44 --- /dev/null +++ "b/assets/Framework_Vue_Vite\345\216\237\347\220\206\345\255\246\344\271\240.md.8895a11d.lean.js" @@ -0,0 +1 @@ +import{_ as a,o as l,c as i,k as e,a as t}from"./chunks/framework.c53372a0.js";const k=JSON.parse('{"title":"Vite底层原理学习","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/Vite原理学习.md","filePath":"Framework/Vue/Vite原理学习.md"}'),s={name:"Framework/Vue/Vite原理学习.md"},o=e("h1",{id:"vite底层原理学习",tabindex:"-1"},[t("Vite底层原理学习 "),e("a",{class:"header-anchor",href:"#vite底层原理学习","aria-label":'Permalink to "Vite底层原理学习"'},"​")],-1),r=e("h2",{id:"构建工具承担",tabindex:"-1"},[t("构建工具承担: "),e("a",{class:"header-anchor",href:"#构建工具承担","aria-label":'Permalink to "构建工具承担:"'},"​")],-1),n=e("ol",null,[e("li",null,"模块化开发支持:ES Module、CommonJS、AMD、CMD等"),e("li",null,"处理代码兼容性:babel语法降级,less/sass/stylus等语法转换"),e("li",null,"提升项目性能:压缩代码,合并代码,图片压缩,代码分割,懒加载,预加载等"),e("li",null,"优化开发体验:热更新,自动刷新,代理服务器,自动打开浏览器等"),e("li",null,"统一开发标准:eslint代码检查,prettier代码格式化,git提交规范等")],-1),c=[o,r,n];function d(_,h,m,u,p,V){return l(),i("div",null,c)}const b=a(s,[["render",d]]);export{k as __pageData,b as default}; diff --git "a/assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.js" "b/assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.js" new file mode 100644 index 00000000..fc7f64f7 --- /dev/null +++ "b/assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.js" @@ -0,0 +1,97 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/Vue3补漏笔记.md","filePath":"Framework/Vue/Vue3补漏笔记.md"}'),p={name:"Framework/Vue/Vue3补漏笔记.md"},o=l(`

inheritAttrs

唯一一个需要用额外的 script 块书写的选项

$attrs

透传 Attributes 是指由父组件传入,且没有被子组件声明为 props 或是 组件自定义事件的 attributes 和 事件处理函数。

html
<template> 
+  <Home :attr="12345" :val="false"/>
+</template>
<template> 
+  <Home :attr="12345" :val="false"/>
+</template>

场景一:

html
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: true,//默认继承父组件属性
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: true,//默认继承父组件属性
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>

image-20230219215449385

场景二:

html
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)
+	  }
+  }
+</script>

image-20230219215459359

场景三:

html
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)//输出被props接收以外的属性
+	  }
+    props: ['val']
+  }
+</script>
<template>
+  <div class="home">
+    Home work!
+  </div>
+</template>
+<script setup lang='ts'>
+
+</script>
+<script>
+  export default {
+    inheritAttrs: fasle,//取消继承
+    mounted() {
+      console.log('this.$attrs', this.$attrs)//输出被props接收以外的属性
+	  }
+    props: ['val']
+  }
+</script>

image-20230219215510922

`,13),t=[o];function e(c,r,y,i,D,A){return a(),n("div",null,t)}const C=s(p,[["render",e]]);export{B as __pageData,C as default}; diff --git "a/assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.lean.js" "b/assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.lean.js" new file mode 100644 index 00000000..38078a19 --- /dev/null +++ "b/assets/Framework_Vue_Vue3\350\241\245\346\274\217\347\254\224\350\256\260.md.6422a5f9.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/Vue3补漏笔记.md","filePath":"Framework/Vue/Vue3补漏笔记.md"}'),p={name:"Framework/Vue/Vue3补漏笔记.md"},o=l("",13),t=[o];function e(c,r,y,i,D,A){return a(),n("div",null,t)}const C=s(p,[["render",e]]);export{B as __pageData,C as default}; diff --git "a/assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.js" "b/assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.js" new file mode 100644 index 00000000..bd26085a --- /dev/null +++ "b/assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.js" @@ -0,0 +1,337 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"分页与搜索条件记录并回显优化","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/分页与搜索条件记录并回显优化.md","filePath":"Framework/Vue/分页与搜索条件记录并回显优化.md"}'),l={name:"Framework/Vue/分页与搜索条件记录并回显优化.md"},o=p(`

分页与搜索条件记录并回显优化

整体逻辑

image-20230215205106488

Store

js
export default new Vuex.Store({
+    state: {
+        pageOptions: {
+            background:true,
+            layout: 'prev, pager, next, jumper, sizes, total',
+            pageSizes: [10, 20, 30, 50]
+        },
+    }
+}
export default new Vuex.Store({
+    state: {
+        pageOptions: {
+            background:true,
+            layout: 'prev, pager, next, jumper, sizes, total',
+            pageSizes: [10, 20, 30, 50]
+        },
+    }
+}

Mixins

js
import { mapState } from 'vuex'
+export default {
+	data() {
+		return {
+			wrapperLoading: false,
+			gridLoading: false,
+			isEchoCond: false,//回显开关(某些页面特殊需要特殊处理)
+			searchConds: [],
+			paginationOptions: {
+				currentPage: 1,
+				pageSize: 10,
+				total: 0,
+			},
+		}
+	},
+  computed: {
+		...mapState(["pageOptions"]),
+	},
+	methods: {
+		//搜索
+		search(conds) {
+			this.searchConds = conds
+			const query = this.$route.query;
+			let newQuery = Object.assign({}, query, { conds: JSON.stringify(conds), page: 1 })
+			this.$router.push({
+				query: newQuery,
+		 });
+		},
+		//每页数量改变
+		sizeChange(size, queryFn) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { size, page: 1 }),
+			})
+		},
+		//页码改变
+		currentChange(page) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { page }),
+			})
+			this.paginationOptions.currentPage = page
+		},
+		//从query中获取分页信息
+    initPage(){
+			let { page, size ,conds} = this.$route.query
+      this.paginationOptions.currentPage = page ?  parseInt(page) : 1
+			this.paginationOptions.pageSize = size ?  parseInt(size) : 10
+			conds = conds ? conds : '[]';
+			if (this.isEchoCond) {
+				 this.searchConds = JSON.parse(conds);
+				 this.initSearchFromCond(this.searchConds);
+			 } 
+		},
+		//回显搜索条件
+		initSearchFromCond(conds) {
+      const group = [];
+      this.relateOptions?.forEach(options => {
+        const nameArr = options.list.map( item => item.name);
+				options.model.value = ''
+        group.push(nameArr);
+      });
+      conds.forEach(cond => {
+				group.forEach((g, i) => {
+					if(g.includes(cond.name)) {
+						const obj = {name: '', op: '', value: ''};
+						obj.name = cond.name;
+						obj.op = cond.op;
+						obj.value = cond.op === 'like' ? cond.value.replace(/^%|%$/g, '') : cond.value;
+						this.relateOptions[i].model = obj;
+					}
+				});
+      });
+    },
+	},
+}
import { mapState } from 'vuex'
+export default {
+	data() {
+		return {
+			wrapperLoading: false,
+			gridLoading: false,
+			isEchoCond: false,//回显开关(某些页面特殊需要特殊处理)
+			searchConds: [],
+			paginationOptions: {
+				currentPage: 1,
+				pageSize: 10,
+				total: 0,
+			},
+		}
+	},
+  computed: {
+		...mapState(["pageOptions"]),
+	},
+	methods: {
+		//搜索
+		search(conds) {
+			this.searchConds = conds
+			const query = this.$route.query;
+			let newQuery = Object.assign({}, query, { conds: JSON.stringify(conds), page: 1 })
+			this.$router.push({
+				query: newQuery,
+		 });
+		},
+		//每页数量改变
+		sizeChange(size, queryFn) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { size, page: 1 }),
+			})
+		},
+		//页码改变
+		currentChange(page) {
+			const query = this.$route.query
+			this.$router.push({
+				query: Object.assign({}, query, { page }),
+			})
+			this.paginationOptions.currentPage = page
+		},
+		//从query中获取分页信息
+    initPage(){
+			let { page, size ,conds} = this.$route.query
+      this.paginationOptions.currentPage = page ?  parseInt(page) : 1
+			this.paginationOptions.pageSize = size ?  parseInt(size) : 10
+			conds = conds ? conds : '[]';
+			if (this.isEchoCond) {
+				 this.searchConds = JSON.parse(conds);
+				 this.initSearchFromCond(this.searchConds);
+			 } 
+		},
+		//回显搜索条件
+		initSearchFromCond(conds) {
+      const group = [];
+      this.relateOptions?.forEach(options => {
+        const nameArr = options.list.map( item => item.name);
+				options.model.value = ''
+        group.push(nameArr);
+      });
+      conds.forEach(cond => {
+				group.forEach((g, i) => {
+					if(g.includes(cond.name)) {
+						const obj = {name: '', op: '', value: ''};
+						obj.name = cond.name;
+						obj.op = cond.op;
+						obj.value = cond.op === 'like' ? cond.value.replace(/^%|%$/g, '') : cond.value;
+						this.relateOptions[i].model = obj;
+					}
+				});
+      });
+    },
+	},
+}

列表页 xxxList.vue

js
data() {
+	return {
+		relateOptions: [
+				{
+					inputWidth: "200px",
+					list: [
+						{
+							name: "number",
+							op: "=",
+							label: "序号",
+							placeholder: "情输入序号",
+						},
+						{
+							name: "name",
+							op: "like",
+							label: "名称",
+							placeholder: "请输入名称",
+						},
+						{
+							name: "esn",
+							op: "like",
+							label: "ESN",
+							placeholder: "请输入ESN",
+						},
+						{
+							name: "status.status",
+							op: "=",
+							label: "状态",
+							valueList: [
+								{
+									name: "",
+									label: "全部",
+								},
+								{
+									name: "Online",
+									label: "在线",
+								},
+								{
+									name: "Offline",
+									label: "离线",
+								},
+							],
+						},
+					],
+					model: { name: "number", op: "like", value: "" },
+				},
+			],
+}
+mixins: [listPage],
+watch: {
+		'$route.query':{
+      immediate:true,
+      deep:true,
+      handler(){
+					this.initPage()
+					this.queryXXX();
+      }
+    },
+	},
+    
+methods: {
+		async queryXXX() {
+			this.gridLoading = true
+		  const qobj = {}
+			qobj.conditions = this.searchConds
+      
+			let { pageSize, currentPage } = this.paginationOptions
+			qobj.limit = pageSize
+			qobj.start = (currentPage - 1) * pageSize
+
+			const result = await queryXXX(qobj)
+			if (result.success && result.inventories.length) {
+			this.xxxList = result.success ? result.inventories : []
+			this.paginationOptions.total = result.success ? result.total : 0
+			this.gridLoading = false
+		},
+		searchCondDone(conds) {
+			this.search(conds)
+		},
+		handleSizeChange(size) {
+			this.sizeChange(size)
+		},
+		handleCurrentChange(page) {
+		  this.currentChange(page)
+		},
+   }
data() {
+	return {
+		relateOptions: [
+				{
+					inputWidth: "200px",
+					list: [
+						{
+							name: "number",
+							op: "=",
+							label: "序号",
+							placeholder: "情输入序号",
+						},
+						{
+							name: "name",
+							op: "like",
+							label: "名称",
+							placeholder: "请输入名称",
+						},
+						{
+							name: "esn",
+							op: "like",
+							label: "ESN",
+							placeholder: "请输入ESN",
+						},
+						{
+							name: "status.status",
+							op: "=",
+							label: "状态",
+							valueList: [
+								{
+									name: "",
+									label: "全部",
+								},
+								{
+									name: "Online",
+									label: "在线",
+								},
+								{
+									name: "Offline",
+									label: "离线",
+								},
+							],
+						},
+					],
+					model: { name: "number", op: "like", value: "" },
+				},
+			],
+}
+mixins: [listPage],
+watch: {
+		'$route.query':{
+      immediate:true,
+      deep:true,
+      handler(){
+					this.initPage()
+					this.queryXXX();
+      }
+    },
+	},
+    
+methods: {
+		async queryXXX() {
+			this.gridLoading = true
+		  const qobj = {}
+			qobj.conditions = this.searchConds
+      
+			let { pageSize, currentPage } = this.paginationOptions
+			qobj.limit = pageSize
+			qobj.start = (currentPage - 1) * pageSize
+
+			const result = await queryXXX(qobj)
+			if (result.success && result.inventories.length) {
+			this.xxxList = result.success ? result.inventories : []
+			this.paginationOptions.total = result.success ? result.total : 0
+			this.gridLoading = false
+		},
+		searchCondDone(conds) {
+			this.search(conds)
+		},
+		handleSizeChange(size) {
+			this.sizeChange(size)
+		},
+		handleCurrentChange(page) {
+		  this.currentChange(page)
+		},
+   }
`,9),t=[o];function e(c,r,y,A,D,B){return n(),a("div",null,t)}const C=s(l,[["render",e]]);export{i as __pageData,C as default}; diff --git "a/assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.lean.js" "b/assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.lean.js" new file mode 100644 index 00000000..9108b41f --- /dev/null +++ "b/assets/Framework_Vue_\345\210\206\351\241\265\344\270\216\346\220\234\347\264\242\346\235\241\344\273\266\350\256\260\345\275\225\345\271\266\345\233\236\346\230\276\344\274\230\345\214\226.md.8805bdc2.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"分页与搜索条件记录并回显优化","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/分页与搜索条件记录并回显优化.md","filePath":"Framework/Vue/分页与搜索条件记录并回显优化.md"}'),l={name:"Framework/Vue/分页与搜索条件记录并回显优化.md"},o=p("",9),t=[o];function e(c,r,y,A,D,B){return n(),a("div",null,t)}const C=s(l,[["render",e]]);export{i as __pageData,C as default}; diff --git "a/assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.js" "b/assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.js" new file mode 100644 index 00000000..12ca9dfb --- /dev/null +++ "b/assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.js" @@ -0,0 +1,79 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"一、删除最后一条数据跳转到上一页","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/列表最后一条数据删除处理.md","filePath":"Framework/Vue/列表最后一条数据删除处理.md"}'),l={name:"Framework/Vue/列表最后一条数据删除处理.md"},o=p(`

一、删除最后一条数据跳转到上一页

方案一

js
/*
+paginationOptions: {
+    currentPage: 1,
+    pageSize: 10,
+    total: 0,
+},
+*/
+async removeDone() {
+    this.wrapperLoading = true
+    const { name, uuid } = this.currentRow
+    const { success } = await removeAccount({ uuid })
+    this.wrapperLoading = false
+    if (success) {
+        this.$notify({
+            type: "success",
+            message: \`账号\${name}删除成功\`,
+        })
+        //方案一: 判断是否为最后一条数据 并且总数据不能小于1
+        let {total,currentPage} = this.paginationOptions.currentPage
+        	if (this.contactsData.length === 1 &&  total > 1) {
+            this.paginationOptions.currentPage = currentPage - 1
+        }
+        
+        //方案二:
+          let { currentPage,pageSize,total} = this.paginationOptions
+          //求删除后还有几页
+          let deleteAfterPage = Math.ceil((total - 1) / pageSize)
+          //若删除后页数小于当前页, 取删除后的页数;否则不变
+          let curPage = currentPage > deleteAfterPage ? deleteAfterPage : currentPage
+          //当前页只有一页则为1,否则取计算得到的页
+          this.paginationOptions.currentPage = curPage < 2 ? 1 : curPage
+        
+        this.queryAccount()
+    } else {
+        this.$notify({
+            type: "error",
+            message: \`账号\${name}删除失败\`,
+        })
+    }
+},
/*
+paginationOptions: {
+    currentPage: 1,
+    pageSize: 10,
+    total: 0,
+},
+*/
+async removeDone() {
+    this.wrapperLoading = true
+    const { name, uuid } = this.currentRow
+    const { success } = await removeAccount({ uuid })
+    this.wrapperLoading = false
+    if (success) {
+        this.$notify({
+            type: "success",
+            message: \`账号\${name}删除成功\`,
+        })
+        //方案一: 判断是否为最后一条数据 并且总数据不能小于1
+        let {total,currentPage} = this.paginationOptions.currentPage
+        	if (this.contactsData.length === 1 &&  total > 1) {
+            this.paginationOptions.currentPage = currentPage - 1
+        }
+        
+        //方案二:
+          let { currentPage,pageSize,total} = this.paginationOptions
+          //求删除后还有几页
+          let deleteAfterPage = Math.ceil((total - 1) / pageSize)
+          //若删除后页数小于当前页, 取删除后的页数;否则不变
+          let curPage = currentPage > deleteAfterPage ? deleteAfterPage : currentPage
+          //当前页只有一页则为1,否则取计算得到的页
+          this.paginationOptions.currentPage = curPage < 2 ? 1 : curPage
+        
+        this.queryAccount()
+    } else {
+        this.$notify({
+            type: "error",
+            message: \`账号\${name}删除失败\`,
+        })
+    }
+},
`,3),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const C=s(l,[["render",t]]);export{i as __pageData,C as default}; diff --git "a/assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.lean.js" "b/assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.lean.js" new file mode 100644 index 00000000..f749dce9 --- /dev/null +++ "b/assets/Framework_Vue_\345\210\227\350\241\250\346\234\200\345\220\216\344\270\200\346\235\241\346\225\260\346\215\256\345\210\240\351\231\244\345\244\204\347\220\206.md.9f59b85b.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"一、删除最后一条数据跳转到上一页","description":"","frontmatter":{},"headers":[],"relativePath":"Framework/Vue/列表最后一条数据删除处理.md","filePath":"Framework/Vue/列表最后一条数据删除处理.md"}'),l={name:"Framework/Vue/列表最后一条数据删除处理.md"},o=p("",3),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const C=s(l,[["render",t]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.js" "b/assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.js" new file mode 100644 index 00000000..6285e8d3 --- /dev/null +++ "b/assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.js" @@ -0,0 +1,235 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"Grid布局学习笔记","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/CSS/Grid布局学习笔记.md","filePath":"FrontEnd/CSS/Grid布局学习笔记.md"}'),p={name:"FrontEnd/CSS/Grid布局学习笔记.md"},o=l(`

Grid布局学习笔记

实用网站

基本概念

image-20230216202917923

image-20230216203121127

容器属性

开启 Grid布局

css
.box{
+  display:grid;
+}
.box{
+  display:grid;
+}

容器划分行列

  1. 取值为数值 grid-template-rows:100px 100px 100px
  2. 取值为百分比 grid-template-rows:20% 30% 50%
  3. 重复函数 grid-template-rows:repeat(3,20%)
  4. 自动填充 grid-template-rows:repeat(auto-fill, 30%)
  5. auto自动 grid-template-rows:100px auto 100px
  6. fr片段划分 grid-template-rows:1fr 2fr 1fr
  7. minmax() grid-template-rows:200px 200px minmax(100px,200px)

image-20230216205607291

image-20230216205635684

image-20230216205710712

image-20230216205031540

image-20230216205043840

image-20230216205247964

image-20230216205743766

调整间距属性

css
.box{
+  /* 写法一:*/
+  grid-row-gap:20px;
+  grid-column-gap:30px;
+
+   /* 写法二:*/
+  grid-gap:20px 30px;
+
+   /* 写法三:*/
+  gap:20px 30px;
+
+}
.box{
+  /* 写法一:*/
+  grid-row-gap:20px;
+  grid-column-gap:30px;
+
+   /* 写法二:*/
+  grid-gap:20px 30px;
+
+   /* 写法三:*/
+  gap:20px 30px;
+
+}

image-20230216210259623

容器内网格对齐方式

解释

网格相对于容器的对齐方式

css
.box{
+  /*justify-content:space-around;
+  align-content:space-evenly;*/
+  palce-content:space-around space-evenly;
+}
.box{
+  /*justify-content:space-around;
+  align-content:space-evenly;*/
+  palce-content:space-around space-evenly;
+}

image-20230216212726986

案例

css
.box{
+  justify-content:center; 
+   align-content: center;
+}
.box{
+  justify-content:center; 
+   align-content: center;
+}

image-20230216223101040

网格内项目对其方式

解释

项目相对于网格/区域的对齐方式

js
.box{
+  justify-items:center;    //start, end
+  align-items:center;    //start, end
+  //place-items:center center //水平 垂直
+}
.box{
+  justify-items:center;    //start, end
+  align-items:center;    //start, end
+  //place-items:center center //水平 垂直
+}

image-20230216211850992

案例:

html
 <div class="box">
+      <div class="item a"></div>
+      <div class="item b"></div>
+      <div class="item c"></div>
+    </div>
 <div class="box">
+      <div class="item a"></div>
+      <div class="item b"></div>
+      <div class="item c"></div>
+    </div>
css
     .box {
+        width: 800px;
+        height: 800px;
+        display: grid;
+        grid-template-columns: repeat(3, 100px);
+        grid-template-rows: repeat(3, 100px);
+        align-items: center;
+        justify-items: center;
+        grid-gap: 10px;
+        grid-template-areas:
+          "a a a"
+          ". b b"
+          "c c c";
+      }
+      .item{
+        width: 50px ;
+        height: 50px;
+        border:1px dashed #000;
+
+      }
+      .a{
+        grid-area: a;
+      }
+      .b{
+        grid-area: b;
+      }
+      .c{
+        grid-area: c;
+      }
     .box {
+        width: 800px;
+        height: 800px;
+        display: grid;
+        grid-template-columns: repeat(3, 100px);
+        grid-template-rows: repeat(3, 100px);
+        align-items: center;
+        justify-items: center;
+        grid-gap: 10px;
+        grid-template-areas:
+          "a a a"
+          ". b b"
+          "c c c";
+      }
+      .item{
+        width: 50px ;
+        height: 50px;
+        border:1px dashed #000;
+
+      }
+      .a{
+        grid-area: a;
+      }
+      .b{
+        grid-area: b;
+      }
+      .c{
+        grid-area: c;
+      }

image-20230216222635254

项目排列顺序

image-20230216210624604

容器中区域定义

html
<div class="box">
+  <div class="item a"></div>
+  <div class="item b"></div>
+  <div class="item c"></div>
+</div>
<div class="box">
+  <div class="item a"></div>
+  <div class="item b"></div>
+  <div class="item c"></div>
+</div>
css
.box {
+    width: 800px;
+    height: 800px;
+    display: grid;
+    grid-template-columns: repeat(3, 100px);
+    grid-template-rows: repeat(3, 100px);
+    align-content: center;
+    justify-content: center;
+    grid-gap: 10px;
+    grid-template-areas:
+      "a a a"
+      ". b b"
+      "c c c";
+  }
+  .item{
+    border:1px dashed #000;
+  }
+  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }
.box {
+    width: 800px;
+    height: 800px;
+    display: grid;
+    grid-template-columns: repeat(3, 100px);
+    grid-template-rows: repeat(3, 100px);
+    align-content: center;
+    justify-content: center;
+    grid-gap: 10px;
+    grid-template-areas:
+      "a a a"
+      ". b b"
+      "c c c";
+  }
+  .item{
+    border:1px dashed #000;
+  }
+  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }

image-20230216220606952

项目属性

合并单元格属性

css
.header{
+  /* 写法一:*/
+  grid-column-start: 1;
+  grid-column-end: 3;
+
+  grid-row-start: 1;
+  grid-row-end: 2;
+
+  /* 写法二:*/
+  grid-column: 1 / 3;
+  grid-row: 1 / 2;
+
+  /* 写法三:使用 span 关键字,表示跨越。表示项目的左边框距离右边框跨越 2 个网格。*/
+  grid-column-start: span 2;
+
+  /* 写法四:若跨度为 1,则可简写第二根网格线*/
+  grid-row: 1 / 2; ==>  grid-row: 1;
+  grid-row: 3 / 4; ==>  grid-row: 3;
+}
.header{
+  /* 写法一:*/
+  grid-column-start: 1;
+  grid-column-end: 3;
+
+  grid-row-start: 1;
+  grid-row-end: 2;
+
+  /* 写法二:*/
+  grid-column: 1 / 3;
+  grid-row: 1 / 2;
+
+  /* 写法三:使用 span 关键字,表示跨越。表示项目的左边框距离右边框跨越 2 个网格。*/
+  grid-column-start: span 2;
+
+  /* 写法四:若跨度为 1,则可简写第二根网格线*/
+  grid-row: 1 / 2; ==>  grid-row: 1;
+  grid-row: 3 / 4; ==>  grid-row: 3;
+}

image-20230216213656308

项目区域定义

css
  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }
  .a{
+    grid-area: a;
+  }
+  .b{
+    grid-area: b;
+  }
+  .c{
+    grid-area: c;
+  }

grid-area

grid-area 属性还可用作 grid-row-startgrid-column-startgrid-row-endgrid-column-end 的合并简写形式,直接指定项目的位置。

css
.item {
+  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
+}
.item {
+  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
+}

单个项目位置

justify-self 和 align-self

justify-self 属性设置单元格内容的水平位置(左中右),跟 justify-items 属性的用法完全一致,但只作用于单个项目。

align-self 属性设置单元格内容的垂直位置(上中下),跟 align-items 属性的用法完全一致,也是只作用于单个项目。

css
.item {
+  justify-self: start | end | center | stretch;
+  align-self: start | end | center | stretch;
+  /* 简写 place-self: <align-self> <justify-self>; */
+}
.item {
+  justify-self: start | end | center | stretch;
+  align-self: start | end | center | stretch;
+  /* 简写 place-self: <align-self> <justify-self>; */
+}
`,54),e=[o];function c(t,r,y,i,A,D){return a(),n("div",null,e)}const E=s(p,[["render",c]]);export{B as __pageData,E as default}; diff --git "a/assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.lean.js" "b/assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.lean.js" new file mode 100644 index 00000000..362f0366 --- /dev/null +++ "b/assets/FrontEnd_CSS_Grid\345\270\203\345\261\200\345\255\246\344\271\240\347\254\224\350\256\260.md.6624dd93.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"Grid布局学习笔记","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/CSS/Grid布局学习笔记.md","filePath":"FrontEnd/CSS/Grid布局学习笔记.md"}'),p={name:"FrontEnd/CSS/Grid布局学习笔记.md"},o=l("",54),e=[o];function c(t,r,y,i,A,D){return a(),n("div",null,e)}const E=s(p,[["render",c]]);export{B as __pageData,E as default}; diff --git "a/assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.js" "b/assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.js" new file mode 100644 index 00000000..4c6ce073 --- /dev/null +++ "b/assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.js" @@ -0,0 +1,175 @@ +import{D as A}from"./chunks/DemoWrap.1b6e7adf.js";import{d as i,h as D,C as B,o as p,c as o,k as l,H as e,N as E,F as C,p as d,m as h,_ as u,w as g,Q as t}from"./chunks/framework.c53372a0.js";const c=s=>(d("data-v-b64031fa"),s=s(),h(),s),v=c(()=>l("pattern",{id:"pattern-1",x:"0",y:"0",width:"24",height:"24",patternUnits:"userSpaceOnUse",patternTransform:"translate(-0.5,-0.5)"},[l("circle",{cx:"0.5",cy:"0.5",r:"0.5",fill:"#60606F"})],-1)),b=c(()=>l("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:"url(#pattern-1)"},null,-1)),f=[v,b],m=i({__name:"GridStar",setup(s){const n=D(!0);return(r,a)=>{const y=B("radio");return p(),o(C,null,[l("p",null,[e(y)]),(p(),o("svg",{onClick:a[0]||(a[0]=F=>n.value=!n.value),style:E({backgroundColor:n.value?"#13121a":"#fff"})},f,4))],64)}}});const q=u(m,[["__scopeId","data-v-b64031fa"]]),_=t(`

CSS常用代码段

单行与多行溢出隐藏

css
.text {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
.text {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
css
.text {
+    display: -webkit-box;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -webkit-box-orient: vertical;/* 布局方向 */
+    -webkit-line-clamp: 3; /* 显示三行文本 */
+}
.text {
+    display: -webkit-box;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -webkit-box-orient: vertical;/* 布局方向 */
+    -webkit-line-clamp: 3; /* 显示三行文本 */
+}

自定义滚动条

css
html,
+body {
+  /* 隐藏滚动条 */
+  scrollbar-width: none; /* firefox */
+  -ms-overflow-style: none; /* IE 10+ */
+  &::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+}
+
+ /* 自定义滚动条 */
+body{
+  overflow: auto;
+  scrollbar-width: none; /* Firefox */
+  &::-webkit-scrollbar {
+    width: 5px;
+    height: 5px;
+  }
+  &::-webkit-scrollbar-track-piece {
+    background-color: rgba($color: #000000, $alpha: .3);
+  }
+  &::-webkit-scrollbar-thumb:vertical {
+    height: 5px;
+    background-color: #0085F9;
+    border-radius: 6px;
+  }
+}
html,
+body {
+  /* 隐藏滚动条 */
+  scrollbar-width: none; /* firefox */
+  -ms-overflow-style: none; /* IE 10+ */
+  &::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+}
+
+ /* 自定义滚动条 */
+body{
+  overflow: auto;
+  scrollbar-width: none; /* Firefox */
+  &::-webkit-scrollbar {
+    width: 5px;
+    height: 5px;
+  }
+  &::-webkit-scrollbar-track-piece {
+    background-color: rgba($color: #000000, $alpha: .3);
+  }
+  &::-webkit-scrollbar-thumb:vertical {
+    height: 5px;
+    background-color: #0085F9;
+    border-radius: 6px;
+  }
+}

画布网状满天星背景

html
<svg >
+  <pattern
+    id="pattern-1"
+    x="0"
+    y="0"
+    width="24"
+    height="24"
+    patternUnits="userSpaceOnUse"
+    patternTransform="translate(-0.5,-0.5)"
+  >
+    <circle cx="0.5" cy="0.5" r="0.5" fill="#60606F"></circle>
+  </pattern>
+  <rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-1)"></rect>
+</svg>
<svg >
+  <pattern
+    id="pattern-1"
+    x="0"
+    y="0"
+    width="24"
+    height="24"
+    patternUnits="userSpaceOnUse"
+    patternTransform="translate(-0.5,-0.5)"
+  >
+    <circle cx="0.5" cy="0.5" r="0.5" fill="#60606F"></circle>
+  </pattern>
+  <rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-1)"></rect>
+</svg>
css
svg {
+  margin-top: 20px;
+  width: 100%;
+  height: 200px;
+  background-color:#13121a;
+}
svg {
+  margin-top: 20px;
+  width: 100%;
+  height: 200px;
+  background-color:#13121a;
+}
`,9),k=t(`

轮播闪光

css
.shine::before {
+  content: '';
+  position: absolute;
+  top: -50%;
+  left: -50%;
+  width: 200%;
+  height: 200%;
+  background: linear-gradient(to bottom right,
+      rgba(255, 255, 255, 0.3),
+      rgba(255, 255, 255, 0.15),
+      rgba(255, 255, 255, 0));
+  transform: rotate(-45deg);
+  animation: shine 2s ease-in-out infinite;
+}
+
+@keyframes shine {
+  from {
+    left: -200%;
+  }
+
+  to {
+    left: 150%;
+  }
+
+}
.shine::before {
+  content: '';
+  position: absolute;
+  top: -50%;
+  left: -50%;
+  width: 200%;
+  height: 200%;
+  background: linear-gradient(to bottom right,
+      rgba(255, 255, 255, 0.3),
+      rgba(255, 255, 255, 0.15),
+      rgba(255, 255, 255, 0));
+  transform: rotate(-45deg);
+  animation: shine 2s ease-in-out infinite;
+}
+
+@keyframes shine {
+  from {
+    left: -200%;
+  }
+
+  to {
+    left: 150%;
+  }
+
+}

flex布局子元素给了高度,实际渲染确有小数点问题

css
.parent{
+  display: flex;
+  flex-direction: column;
+}
+.child{
+  height: 100%;
+}
+.child1{
+    flex: 1; //需要给相邻元素添加
+}
.parent{
+  display: flex;
+  flex-direction: column;
+}
+.child{
+  height: 100%;
+}
+.child1{
+    flex: 1; //需要给相邻元素添加
+}
`,6),T=JSON.parse('{"title":"CSS常用代码段","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/CSS/常用代码段.md","filePath":"FrontEnd/CSS/常用代码段.md"}'),x={name:"FrontEnd/CSS/常用代码段.md"},P=Object.assign(x,{setup(s){return(n,r)=>{const a=A;return p(),o("div",null,[_,e(a,{pkg:"FrontEnd/CSS/demo",path:"GridStar.vue"},{default:g(()=>[e(q)]),_:1}),k])}}});export{T as __pageData,P as default}; diff --git "a/assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.lean.js" "b/assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.lean.js" new file mode 100644 index 00000000..fc44f93c --- /dev/null +++ "b/assets/FrontEnd_CSS_\345\270\270\347\224\250\344\273\243\347\240\201\346\256\265.md.083fb786.lean.js" @@ -0,0 +1 @@ +import{D as A}from"./chunks/DemoWrap.1b6e7adf.js";import{d as i,h as D,C as B,o as p,c as o,k as l,H as e,N as E,F as C,p as d,m as h,_ as u,w as g,Q as t}from"./chunks/framework.c53372a0.js";const c=s=>(d("data-v-b64031fa"),s=s(),h(),s),v=c(()=>l("pattern",{id:"pattern-1",x:"0",y:"0",width:"24",height:"24",patternUnits:"userSpaceOnUse",patternTransform:"translate(-0.5,-0.5)"},[l("circle",{cx:"0.5",cy:"0.5",r:"0.5",fill:"#60606F"})],-1)),b=c(()=>l("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:"url(#pattern-1)"},null,-1)),f=[v,b],m=i({__name:"GridStar",setup(s){const n=D(!0);return(r,a)=>{const y=B("radio");return p(),o(C,null,[l("p",null,[e(y)]),(p(),o("svg",{onClick:a[0]||(a[0]=F=>n.value=!n.value),style:E({backgroundColor:n.value?"#13121a":"#fff"})},f,4))],64)}}});const q=u(m,[["__scopeId","data-v-b64031fa"]]),_=t("",9),k=t("",6),T=JSON.parse('{"title":"CSS常用代码段","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/CSS/常用代码段.md","filePath":"FrontEnd/CSS/常用代码段.md"}'),x={name:"FrontEnd/CSS/常用代码段.md"},P=Object.assign(x,{setup(s){return(n,r)=>{const a=A;return p(),o("div",null,[_,e(a,{pkg:"FrontEnd/CSS/demo",path:"GridStar.vue"},{default:g(()=>[e(q)]),_:1}),k])}}});export{T as __pageData,P as default}; diff --git "a/assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.js" "b/assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.js" new file mode 100644 index 00000000..f07edd5a --- /dev/null +++ "b/assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.js" @@ -0,0 +1,341 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"妙妙怪的《CSS 揭秘》读书摘要","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/CSS/揭秘读书摘要.md","filePath":"FrontEnd/CSS/揭秘读书摘要.md"}'),p={name:"FrontEnd/CSS/揭秘读书摘要.md"},o=l(`

妙妙怪的《CSS 揭秘》读书摘要

看这本书前:看书,现在短视频时代,正经人谁看书啊,要看也是看视频教程和大佬博客啊!

看完这本后:似乎有一点香!(轻松有趣)

从这本书字里行间可以感受到作者也是个有趣的灵魂。

看了这本书知识浅显易懂、挺有趣的,重新让我拾回看书的一些兴趣;

这本书让我感受到 CSS 一些巧妙的技巧,故摘抄以便往后快捷运用。

背景与边框

多重边框

css
box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink, 0 2px 5px 15px #ccc;
box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink, 0 2px 5px 15px #ccc;

image-20230204162420066

灵活的背景定位

css
background-position:right 20px bottom 10px;//离右侧20px、下边10px
+background-position:calc(100%-20px) calc(100%-10px);
+background-origin:content-box;//以内容盒为准
background-position:right 20px bottom 10px;//离右侧20px、下边10px
+background-position:calc(100%-20px) calc(100%-10px);
+background-origin:content-box;//以内容盒为准

边框内圆角

css
background: tan;
+border-radius: .8em;
+padding: 1em;
+box-shadow: 0 0 0 .4em #655;//扩张半径取圆角的一半
+outline: .4em solid #655;
background: tan;
+border-radius: .8em;
+padding: 1em;
+box-shadow: 0 0 0 .4em #655;//扩张半径取圆角的一半
+outline: .4em solid #655;

条纹背景

css
//横向
+background: linear-gradient(#fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 100% 20px;
+//垂直
+background: linear-gradient(to right, #fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 20px 100%;
+//斜向
+background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #ccc 0, #ccc 75%, #58a 0);
+background-size: 100%;
+//重复任意角度条纹
+ background: repeating-linear-gradient( 60deg, #fb3, #fb3 15px, #58a 0, #58a 30px);
//横向
+background: linear-gradient(#fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 100% 20px;
+//垂直
+background: linear-gradient(to right, #fb3 33.3%, #58a 0, #58a 66.6%, #ccc 0);
+background-size: 20px 100%;
+//斜向
+background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #ccc 0, #ccc 75%, #58a 0);
+background-size: 100%;
+//重复任意角度条纹
+ background: repeating-linear-gradient( 60deg, #fb3, #fb3 15px, #58a 0, #58a 30px);

image-20230204162605711

形状

圆角

css
border-radius:水平半径/垂直半径 
+border-radius: 50% / 100% 0;//树叶形状   
+border-radius: 100% 0 0 100%/50%; //半椭圆
+border-radius: 100% 0 0 0;//四分之一椭圆
border-radius:水平半径/垂直半径 
+border-radius: 50% / 100% 0;//树叶形状   
+border-radius: 100% 0 0 100%/50%; //半椭圆
+border-radius: 100% 0 0 0;//四分之一椭圆

image-20230204162727674

平行四边形

css
/*按钮内容不行变解决方案*/
+button {
+        position: relative;
+        background: transparent;
+        outline: none;
+        border: none;
+        padding: 10px 20px;
+        margin-left: 50px;
+        z-index: 1;
+    }
+
+    button::after {
+        position: absolute;
+        content: '';
+        top: 0;
+        left: 0;
+        bottom: 0;
+        right: 0;
+        width: 90px;
+        height: 35px;
+        display: block;
+        background: #5C7AEA;
+        transform: skewX(-30deg);
+        z-index: -1;
+    }
/*按钮内容不行变解决方案*/
+button {
+        position: relative;
+        background: transparent;
+        outline: none;
+        border: none;
+        padding: 10px 20px;
+        margin-left: 50px;
+        z-index: 1;
+    }
+
+    button::after {
+        position: absolute;
+        content: '';
+        top: 0;
+        left: 0;
+        bottom: 0;
+        right: 0;
+        width: 90px;
+        height: 35px;
+        display: block;
+        background: #5C7AEA;
+        transform: skewX(-30deg);
+        z-index: -1;
+    }

image-20230204162908289

梯形

css
.box {
+    width: 100px;
+    height: 100px;
+    background: rgb(52, 199, 155);
+    margin: 200px auto;
+    position: relative;
+    font-size: 40px;
+    color: #fff;
+    line-height: 100px;
+}
+.box::before {
+    position: absolute;
+    top: -100px;
+    left: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}
+.box::after {
+    position: absolute;
+    top: -100px;
+    right: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}
.box {
+    width: 100px;
+    height: 100px;
+    background: rgb(52, 199, 155);
+    margin: 200px auto;
+    position: relative;
+    font-size: 40px;
+    color: #fff;
+    line-height: 100px;
+}
+.box::before {
+    position: absolute;
+    top: -100px;
+    left: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}
+.box::after {
+    position: absolute;
+    top: -100px;
+    right: -100px;
+    display: block;
+    content: '';
+    width: 0;
+    height: 0;
+    z-index: -1;
+    border: 100px solid transparent;
+    border-bottom-color: rgb(52, 199, 155);
+}

image-20230204163212947

视觉效果

投影大致原理: box-shadow: 2px 3px 4px rgba(0, 0, 0, .5);

  1. 画该元素相同尺寸、位置、指定颜色的矩形
  2. 按指定的 x、y 进行水平垂直位移
  3. 按指定模糊半径,使用高斯模糊算法进行处理
  4. 切除与原始元素交集部分

双侧投影

css
box-shadow: 5px 0 5px -5px #000,-5px 0 5px -5px red
box-shadow: 5px 0 5px -5px #000,-5px 0 5px -5px red

image-20230204163300223

染色效果

css
img {
+    filter: sepia(1) saturate( 4) hue-rotate( 295deg);
+}
img {
+    filter: sepia(1) saturate( 4) hue-rotate( 295deg);
+}

image-20230204163621777

毛玻璃

IE 不支持 Chrome 大于等于 76 Edge 大于等于 17 Firefox 70 至 94

折角效果

css
box {
+            width: 200px;
+            height: 100px;
+            margin: 100px;
+            padding: 20px;
+            position: relative;
+                 border-radius: .5em;
+            background: linear-gradient(210deg, transparent 1.5em, #edb21d);
+        }
+
+        .box::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            right: 0;
+            width: 1.73em;
+            height: 3em;
+            background: linear-gradient(240deg, transparent 50%, #ccc);
+            transform: translateY(-1.3em) rotate(-30deg);
+            transform-origin: bottom right;
+            border-bottom-left-radius: inherit;
+            box-shadow: -0.3em 0.2em 0.3em -0.1em #bbb;
+        }
box {
+            width: 200px;
+            height: 100px;
+            margin: 100px;
+            padding: 20px;
+            position: relative;
+                 border-radius: .5em;
+            background: linear-gradient(210deg, transparent 1.5em, #edb21d);
+        }
+
+        .box::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            right: 0;
+            width: 1.73em;
+            height: 3em;
+            background: linear-gradient(240deg, transparent 50%, #ccc);
+            transform: translateY(-1.3em) rotate(-30deg);
+            transform-origin: bottom right;
+            border-bottom-left-radius: inherit;
+            box-shadow: -0.3em 0.2em 0.3em -0.1em #bbb;
+        }

折角效果 mixin 预处理器

css
@mixin folded-corner($background,$size,$angle:30deg){
+    position:relative;
+    background:$background;
+    background:linear-gradient($angle - 180deg,
+        transparent $size,$background 0);
+    border-radius: .5em;
+    $x:$size / sin($angle);
+    $y:$size / cos($angle);
+
+&::before{
+    content: '';
+    position: absolute;
+    top: 0;right: 0;
+    background: linear-gradient(to left bottom,
+        transparent 50%,
+        rgba(0,0,0,.2) 0,
+        rgba(0,0,0,.4)) 100% 0 no-repeat;
+    width:$y;height:$x;
+    transform:translateY($y-$x) rotate(2*$angle - 90deg);
+    transform-origin:bottom right;
+    border-bottom-left-radius:inherit;
+    box-shadow:-.2em .2em .3em -.1em rgba(0,0,0,.15);
+}
+}
+/*当调用时...*/
+.note{
+    @include folded-corner(#68d,1.3em,60deg);
+}
@mixin folded-corner($background,$size,$angle:30deg){
+    position:relative;
+    background:$background;
+    background:linear-gradient($angle - 180deg,
+        transparent $size,$background 0);
+    border-radius: .5em;
+    $x:$size / sin($angle);
+    $y:$size / cos($angle);
+
+&::before{
+    content: '';
+    position: absolute;
+    top: 0;right: 0;
+    background: linear-gradient(to left bottom,
+        transparent 50%,
+        rgba(0,0,0,.2) 0,
+        rgba(0,0,0,.4)) 100% 0 no-repeat;
+    width:$y;height:$x;
+    transform:translateY($y-$x) rotate(2*$angle - 90deg);
+    transform-origin:bottom right;
+    border-bottom-left-radius:inherit;
+    box-shadow:-.2em .2em .3em -.1em rgba(0,0,0,.15);
+}
+}
+/*当调用时...*/
+.note{
+    @include folded-corner(#68d,1.3em,60deg);
+}

字体排印

插入换行

css
hyphens:manual; / *手工设定。默认值,只有单词中有建议换行符才会换行,即手工在单词中插入 ­ * /
+hyphens:none; / *无。即使单词中有换行符,也不会换行,只会在空白处换行* /
+hyphens:auto; / *自动。浏览器在适当的位置自动插入连字符换行* /
hyphens:manual; / *手工设定。默认值,只有单词中有建议换行符才会换行,即手工在单词中插入 ­ * /
+hyphens:none; / *无。即使单词中有换行符,也不会换行,只会在空白处换行* /
+hyphens:auto; / *自动。浏览器在适当的位置自动插入连字符换行* /

可以结合选择器 + / ~ / not(:first-child) 实现在元素后面添加 ,/ 换行符

css
dd+dt::before{
+    content:'\\A';
+    /*content:',';*/
+    white-space:pre;/*空白会被浏览器保留*/
+
+}
dd+dt::before{
+    content:'\\A';
+    /*content:',';*/
+    white-space:pre;/*空白会被浏览器保留*/
+
+}

文本行斑马线

css
.box{
+     padding: 0 .5em;
+    line-height: 1.2;
+    background: hsl(184, 61%, 76%);
+    background-image: linear-gradient( rgb(230, 230, 230) 50%, transparent 0);
+    background-size: auto 50%;
+    background-origin: content-box;
+    font-family: Consolas, Monaco, monospace;
+}
.box{
+     padding: 0 .5em;
+    line-height: 1.2;
+    background: hsl(184, 61%, 76%);
+    background-image: linear-gradient( rgb(230, 230, 230) 50%, transparent 0);
+    background-size: auto 50%;
+    background-origin: content-box;
+    font-family: Consolas, Monaco, monospace;
+}

image-20230204164506163

自定义下划线

css
.box{
+    background: linear-gradient(gray, gray) no-repeat;
+    background-size: 100% 1px;
+    background-position: 0 1.15em;
+    text-shadow: .05em 0 white, -.05em 0 white;
+}
.box{
+    background: linear-gradient(gray, gray) no-repeat;
+    background-size: 100% 1px;
+    background-position: 0 1.15em;
+    text-shadow: .05em 0 white, -.05em 0 white;
+}

image-20230204164714672

凹凸印刷文字效果

css
text-shadow: 1px 1px 1px #000, -1px -1px 1px #fff;//凸
+text-shadow: -1px -1px 1px #000, 1px 1px 1px #fff;//凹
text-shadow: 1px 1px 1px #000, -1px -1px 1px #fff;//凸
+text-shadow: -1px -1px 1px #000, 1px 1px 1px #fff;//凹

image-20230204165035803

满幅背景、定宽内容(页脚)

css
footer{
+    max-width:1000px;
+    padding:1em calc(50%-500px)
+}
footer{
+    max-width:1000px;
+    padding:1em calc(50%-500px)
+}

紧贴底部的页脚

css
body{
+    display:flex;
+    flex-direction:column;
+    min-height:100vh;
+}
+main{
+    flex:1;
+}
body{
+    display:flex;
+    flex-direction:column;
+    min-height:100vh;
+}
+main{
+    flex:1;
+}

闪烁效果

css
.box{
+  background-color:  pink;
+  animation: twinkle 0.5s infinite steps(2) alternate;/*普通闪烁*/
+  animation: twinkle 0.5s infinite   alternate;  /*真实闪烁*/
+}
+@keyframes twinkle {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}
.box{
+  background-color:  pink;
+  animation: twinkle 0.5s infinite steps(2) alternate;/*普通闪烁*/
+  animation: twinkle 0.5s infinite   alternate;  /*真实闪烁*/
+}
+@keyframes twinkle {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}

2023-02-04 16.57.27

`,61),e=[o];function t(c,r,y,A,i,D){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{B as __pageData,C as default}; diff --git "a/assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.lean.js" "b/assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.lean.js" new file mode 100644 index 00000000..ee760a3d --- /dev/null +++ "b/assets/FrontEnd_CSS_\346\217\255\347\247\230\350\257\273\344\271\246\346\221\230\350\246\201.md.3689a434.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"妙妙怪的《CSS 揭秘》读书摘要","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/CSS/揭秘读书摘要.md","filePath":"FrontEnd/CSS/揭秘读书摘要.md"}'),p={name:"FrontEnd/CSS/揭秘读书摘要.md"},o=l("",61),e=[o];function t(c,r,y,A,i,D){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{B as __pageData,C as default}; diff --git "a/assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.js" "b/assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.js" new file mode 100644 index 00000000..65bd3146 --- /dev/null +++ "b/assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.js" @@ -0,0 +1,115 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const g=JSON.parse('{"title":"Git常用操作","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Git/Git常用操作.md","filePath":"FrontEnd/Git/Git常用操作.md"}'),o={name:"FrontEnd/Git/Git常用操作.md"},p=l(`

Git常用操作

拉取最新提交

zsh
  git fetch -p  #或 git fetch -p origin
  git fetch -p  #或 git fetch -p origin

git fetch -p (或者 --prune)命令用于从远程仓库中拉取最新的提交记录,同时也会删除 本地不存在的远程分支;不会更新本地分支和远程分支之间的关联关系,需要手动执行 git mergegit rebase 命令,或者使用 git pull 命令。例:删除远程 dev分支后,使用此命令,本地的远程分支也会被清理。

git fetch 命令用于将远程仓库中的最新提交记录拉取到本地仓库中,但是不会自动合并(merge)这些提交;不会删除本地不存在的远程分支,可能会导致本地分支列表过长,不便于管理。

删除远程分支

zsh
git branch / git branch -r 	     #列出所有本地/远程分支
+git branch -D 分支名              #删除本地库分支
+git push origin --delete 分支名   #删除远程库分支
git branch / git branch -r 	     #列出所有本地/远程分支
+git branch -D 分支名              #删除本地库分支
+git push origin --delete 分支名   #删除远程库分支

删除Tag

zsh
git tag -l                       #列出所有本地/远程tag
+git tag -D tag名                 #删除本地库tag
+git push origin --delete tag名   #删除远程库tag
+git tag -l | xargs git tag -d   #删除本地所有 tag
git tag -l                       #列出所有本地/远程tag
+git tag -D tag名                 #删除本地库tag
+git push origin --delete tag名   #删除远程库tag
+git tag -l | xargs git tag -d   #删除本地所有 tag

删除远程文件

zsh
git rm -r -n --cached 文件/文件夹名称   #预览要删除的文件列表
+git rm -r --cached 文件/文件夹名称      #确定无误后删除文件
git rm -r -n --cached 文件/文件夹名称   #预览要删除的文件列表
+git rm -r --cached 文件/文件夹名称      #确定无误后删除文件

fork后的仓库,拉取合并原仓库的更新

zsh
git remote add upstream [原仓库URL] #添加上游分支路径
+git pull upstream [分支名]  				#拉取上游分支更新并合并
git remote add upstream [原仓库URL] #添加上游分支路径
+git pull upstream [分支名]  				#拉取上游分支更新并合并

合并多次提交

zsh
git rebase -i HEAD~3        #合并最近的 3 次提交,并开启交互模式
+git rebase -i <commit_sha>  #开启交互模式
git rebase -i HEAD~3        #合并最近的 3 次提交,并开启交互模式
+git rebase -i <commit_sha>  #开启交互模式
zsh
git rebase -i 8fc6389   #填第2 次提交的 hash,则表示合并 2 之后(3和 4)的提交
git rebase -i 8fc6389   #填第2 次提交的 hash,则表示合并 2 之后(3和 4)的提交

image-20230227205854474

把需要压缩的提交 pick 改为 s,必须保留一个 pick,下一步填写合并提交信息,保存退出(:wq)完成合并

image-20230227105523929

image-20230227205916425

关联多个代码托管平台

当本地仓库项同时关联 github 和 gitee,同步更新两边代码

  1. 方法一 git remote add gitee [gitee_repo_url],需要多次推送

效果:

zsh
[branch "master"]
+	remote = origin
+	merge = refs/heads/master
+[remote "origin"]
+	url = git@github.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+[remote "gitee"]
+	url = git@gitee.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/gitee/*
[branch "master"]
+	remote = origin
+	merge = refs/heads/master
+[remote "origin"]
+	url = git@github.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+[remote "gitee"]
+	url = git@gitee.com:fxzer/juejin-server-mysql.git
+	fetch = +refs/heads/*:refs/remotes/gitee/*
zsh
#git remote -v                                                   
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (fetch)
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (push)
+origin  git@github.com:fxzer/juejin-server-mysql.git (fetch)
+origin  git@github.com:fxzer/juejin-server-mysql.git (push)
#git remote -v                                                   
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (fetch)
+gitee   git@gitee.com:fxzer/juejin-server-mysql.git (push)
+origin  git@github.com:fxzer/juejin-server-mysql.git (fetch)
+origin  git@github.com:fxzer/juejin-server-mysql.git (push)
  1. 方法二 git remote set-url --add origin [gitee_repo_url] , 只需一次推送

效果:~

zsh
[remote "origin"]
+	url = git@github.com:fxzer/json-viewer.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+	url = git@gitee.com:fxzer/json-viewer.git
+[branch "master"]
+	remote = origin
+	merge = refs/heads/master
[remote "origin"]
+	url = git@github.com:fxzer/json-viewer.git
+	fetch = +refs/heads/*:refs/remotes/origin/*
+	url = git@gitee.com:fxzer/json-viewer.git
+[branch "master"]
+	remote = origin
+	merge = refs/heads/master
zsh
#git remote -v
+origin  git@github.com:fxzer/json-viewer.git (fetch)
+origin  git@github.com:fxzer/json-viewer.git (push)
+origin  git@gitee.com:fxzer/json-viewer.git (push)
#git remote -v
+origin  git@github.com:fxzer/json-viewer.git (fetch)
+origin  git@github.com:fxzer/json-viewer.git (push)
+origin  git@gitee.com:fxzer/json-viewer.git (push)

git remote addgit remote set-url --add区别

  • git remote add 用于添加一个新的远程仓库。该本地仓库已关联远程库,希望添加新的远程库。**运用:**fork后的仓库,需要拉取合并原仓库的更新。
  • git remote set-url --add 用于向已经存在的远程仓库中添加一个新的 URL。**运用:**同一个仓库关联 github 和 gitee 方便同时更新。
  • git remote set-url 命令会替换掉原有的链接,git remote set-url --add 命令,则是添加一个标识对应的远程库链接。

改错分支但为未提交

zsh
git stash            #暂存更改到stash
+git checkout 分支名   #切换分支
+git stash pop        #从stash中取出暂存的代码修改
git stash            #暂存更改到stash
+git checkout 分支名   #切换分支
+git stash pop        #从stash中取出暂存的代码修改

提交完未推送前,需要再次提交

  • 提交完未推送前,发现代码有的有点小问题,还需要修改再提交,但是不想新增垃圾提交信息,保持简洁。
  • 只需要修改提交的内容而不需要改变提交信息, 可以使用 --no-edit 参数来跳过编辑提交信息的步骤。
zsh
git commit --amend --no-edit # 做的修改合并到最近的提交中,相当于是在原有的提交上进行修改,而不是创建一个新的提交。
+
+# 使用后在拉取代码会出现:位于分支 master
+# 您的分支和 'origin/master' 出现了偏离,
+# 并且分别有 1 和 1 处不同的提交。
+#   (使用 "git pull" 来合并远程分支)
+ git config pull.rebase true   # git pull前,需要执行此命令进行变基
git commit --amend --no-edit # 做的修改合并到最近的提交中,相当于是在原有的提交上进行修改,而不是创建一个新的提交。
+
+# 使用后在拉取代码会出现:位于分支 master
+# 您的分支和 'origin/master' 出现了偏离,
+# 并且分别有 1 和 1 处不同的提交。
+#   (使用 "git pull" 来合并远程分支)
+ git config pull.rebase true   # git pull前,需要执行此命令进行变基

修改第一次提交信息

zsh
git rebase -i --root  #把第一次提交的 pick 改为 edit 后 e
+git rebase --continue
+git rebase pull.rebase true
+git pull
+git push
git rebase -i --root  #把第一次提交的 pick 改为 edit 后 e
+git rebase --continue
+git rebase pull.rebase true
+git pull
+git push

代码提交到了错误的分支

方法一

切换到正确的分支并使用, 将指定的提交复制到当前分支,并将其添加到暂存区

zsh
git cherry-pick [commit]
git cherry-pick [commit]

方法二

使用 git rebase 命令将提交移动到正确的分支上:

  1. 切换到错误分支上:git checkout [error-branch]
  2. 将错误分支上的提交移动到正确分支上:git rebase [correct-branch]
  3. 解决冲突(如果有)
  4. 将更改提交到正确的分支上:git checkout [correct-branch],然后 git merge [error-branch]
  5. 在错误分支git push -f更新远程代码

Git 提交规范化

  • husky: Git 钩子工具,在 Git 提交过程的不同阶段自动运行脚本,以此来实现对代码的验证、格式化、测试等操作
  • @commitlint/cli: 提交信息校验脚手架
  • @commitlint/config-conventional: 定义了 commitlint 默认使用的规范。
  • commitizen: 交互式提交工具
  • conventional-changelog: 规范提交信息、并自动生成变更日志
  • cz-conventional-changelog: git cz 提交规范和 changelog 生成工具

husky 文档

zsh
# 安装
+pnpm dlx husky-init && pnpm install
+# 初始化husky配置,在根目录新增.husky配置文件。初始化配置pre-commit
+
+# 新增一个提交git commit 执行前的钩子(commit-msg)
+npx husky add .husky/commit-msg
# 安装
+pnpm dlx husky-init && pnpm install
+# 初始化husky配置,在根目录新增.husky配置文件。初始化配置pre-commit
+
+# 新增一个提交git commit 执行前的钩子(commit-msg)
+npx husky add .husky/commit-msg

注意:需要 git init后才能初始化,否则报错如下

2023-06-27-20-25-35

@commitlint/cli与@commitlint/config-conventional

zsh
#安装校验脚手架、校验规范
+pnpm i @commitlint/cli @commitlint/config-conventional -D
+
+#添加安装脚本呢
+pnpm set-script '"prepare": "husky install"'
#安装校验脚手架、校验规范
+pnpm i @commitlint/cli @commitlint/config-conventional -D
+
+#添加安装脚本呢
+pnpm set-script '"prepare": "husky install"'
js
//commitlint.config.js (若报错 type:'module')可改:commitlint.config.js ==> commitlint.config.cjs
+module.exports = {
+  extends: ["@commitlint/config-conventional"],
+};
//commitlint.config.js (若报错 type:'module')可改:commitlint.config.js ==> commitlint.config.cjs
+module.exports = {
+  extends: ["@commitlint/config-conventional"],
+};

commitizen

zsh
#全局安装
+npm install -g commitizen
#全局安装
+npm install -g commitizen

cz-conventional-changelog

zsh
#全局安装
+npm install -g cz-conventional-changelog
#全局安装
+npm install -g cz-conventional-changelog

配置 ~/.czrc, 将其设置为 commitizen 的插件。

zsh
{
+  "path": "cz-conventional-changelog"
+}
{
+  "path": "cz-conventional-changelog"
+}

作用:提交代码并生成变更日志

使用 commitizen 提交代码时,会自动启动 cz-conventional-changelog 插件,

并根据 conventional-commit 规范提示用户输入提交信息。

输入完毕后,会自动将提交信息转换成符合规范的格式,并将其写入到 CHANGELOG.md 文件中。

`,61),e=[p];function t(c,r,i,y,A,D){return a(),n("div",null,e)}const h=s(o,[["render",t]]);export{g as __pageData,h as default}; diff --git "a/assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.lean.js" "b/assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.lean.js" new file mode 100644 index 00000000..337c2011 --- /dev/null +++ "b/assets/FrontEnd_Git_Git\345\270\270\347\224\250\346\223\215\344\275\234.md.a0e87468.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const g=JSON.parse('{"title":"Git常用操作","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Git/Git常用操作.md","filePath":"FrontEnd/Git/Git常用操作.md"}'),o={name:"FrontEnd/Git/Git常用操作.md"},p=l("",61),e=[p];function t(c,r,i,y,A,D){return a(),n("div",null,e)}const h=s(o,[["render",t]]);export{g as __pageData,h as default}; diff --git "a/assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.js" "b/assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.js" new file mode 100644 index 00000000..0989d963 --- /dev/null +++ "b/assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.js" @@ -0,0 +1,29 @@ +import{_ as s,o as a,c as o,Q as n}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Git/Terminal终端美化.md","filePath":"FrontEnd/Git/Terminal终端美化.md"}'),l={name:"FrontEnd/Git/Terminal终端美化.md"},p=n(`

安装Oh My Posh

可以先去Microsofe Store 安装winget,会比较方便

bash
winget install JanDeDobbeleer.OhMyPosh
winget install JanDeDobbeleer.OhMyPosh

安装完:

会在C:\\Users\\自己用户名\\AppData\\Local\\Programs\\oh-my-posh\\themes>有很多主题

预览所有主题命令

bash
Get-PoshThemes
Get-PoshThemes

image-20220426123111651

初始化并应用主题

bash
oh-my-posh --init --shell pwsh --config "自己的安装目录\\oh-my-posh\\themes\\schema.json" | Invoke-Expression
+#schema.json ---- 选择themes目录下的一款主题文件
oh-my-posh --init --shell pwsh --config "自己的安装目录\\oh-my-posh\\themes\\schema.json" | Invoke-Expression
+#schema.json ---- 选择themes目录下的一款主题文件

分隔符乱码问题

但会发现分隔符会有乱码的问题

乱码问题解决方式:

安装Nerd Fonts字体,在Terminal>Power Shell选择自己安装的字体,保存重启就生效啦。

PS:刚开始以为没有我常用的JetBrain Mono字体,就没在意这种解决方案,没想到里面字体挺丰富.

配置PowerShell

因为应用的主题只在当前窗口有效果,所以需要配置每次PowerShell启动时都会执行应用主题的脚本

1.打开配置文件方式一

  • 获取到PowerShell配置文件绝对路径
bash
$PROFILE
$PROFILE

image-20220426124525580

  • 找到这个文件位置,打开并添加需要Power Shell启动时执行的脚本,保存文件重新打开Terminal看效果
bash
oh-my-posh --init --shell pwsh --config "自己的安装目录\\oh-my-posh\\themes\\schema.json" | Invoke-Expression
oh-my-posh --init --shell pwsh --config "自己的安装目录\\oh-my-posh\\themes\\schema.json" | Invoke-Expression

2.打开配置文件方式二

如果安装了VS Code,如下命令可以直接打开Power Shell配置文件

bash
code $PROFILE
code $PROFILE

自定义主题

可借鉴的up主题文件:https://gitee.com/NilTor/public/blob/master/oh-my-posh-config.json

更多配置可查看官网配置文档

VS Code终端配置

没有配置打开VS Code终端报错:

bash
The term 'oh-my-posh' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify
+     | that the path is correct and try again.
The term 'oh-my-posh' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify
+     | that the path is correct and try again.
  • 在环境变量新增Oh My Posh路径下bin目录

image-20220426141214178

  • 在设置中配置配置自己安装的Nerd Font终端字体,(这里我填上我安装的是JetBrainsMono Nerd Font Mono)

image-20220426141358102

隐藏提示语

每次打开都会有这四句提示语,想要打开是干干净净的界面。

image-20220426233405476

在PowerShell配置项中添加一个配置 ,配置参数 -NoLogo为隐藏提示语

json
 "commandline": "自己的pwsh.exe的路径 -NoLogo",
 "commandline": "自己的pwsh.exe的路径 -NoLogo",

完整配置参考

json
{
+    "colorScheme": "Campbell",
+    "font": 
+    {
+        "face": "JetBrainsMono Nerd Font Mono"
+    },
+    "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
+    "hidden": false,
+    "name": "PowerShell",
+    "source": "Windows.Terminal.PowershellCore",
+    "commandline": "C:\\\\Program Files\\\\WindowsApps\\\\Microsoft.PowerShell_7.2.2.0_x64__8wekyb3d8bbwe\\\\pwsh.exe -NoLogo",
+    "startingDirectory": null
+}
{
+    "colorScheme": "Campbell",
+    "font": 
+    {
+        "face": "JetBrainsMono Nerd Font Mono"
+    },
+    "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
+    "hidden": false,
+    "name": "PowerShell",
+    "source": "Windows.Terminal.PowershellCore",
+    "commandline": "C:\\\\Program Files\\\\WindowsApps\\\\Microsoft.PowerShell_7.2.2.0_x64__8wekyb3d8bbwe\\\\pwsh.exe -NoLogo",
+    "startingDirectory": null
+}

image-20220426233614912

`,44),e=[p];function t(c,r,y,i,A,D){return a(),o("div",null,e)}const d=s(l,[["render",t]]);export{C as __pageData,d as default}; diff --git "a/assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.lean.js" "b/assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.lean.js" new file mode 100644 index 00000000..d530224d --- /dev/null +++ "b/assets/FrontEnd_Git_Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md.6674896b.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as o,Q as n}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Git/Terminal终端美化.md","filePath":"FrontEnd/Git/Terminal终端美化.md"}'),l={name:"FrontEnd/Git/Terminal终端美化.md"},p=n("",44),e=[p];function t(c,r,y,i,A,D){return a(),o("div",null,e)}const d=s(l,[["render",t]]);export{C as __pageData,d as default}; diff --git "a/assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.js" "b/assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.js" new file mode 100644 index 00000000..6a416839 --- /dev/null +++ "b/assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.js" @@ -0,0 +1,37 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Git/配置多个平台SSH.md","filePath":"FrontEnd/Git/配置多个平台SSH.md"}'),o={name:"FrontEnd/Git/配置多个平台SSH.md"},p=l(`

1.生成公钥和私钥

bash
ssh-keygen -t rsa -C '8888888@qq.com'  #换成自己邮箱,可以随便填,相当于一个标识
+#密码不用填 直接回车
ssh-keygen -t rsa -C '8888888@qq.com'  #换成自己邮箱,可以随便填,相当于一个标识
+#密码不用填 直接回车

image-20220416211353115

ls 查看生成的文件

image-20220416211808297

2.在代码托管平台设置添加公钥

  • 查看生成的公钥.pub文件 例如: cat id_rsa_github_gmail.pub
  • 复制公钥所有内容 ,在github/gitee/gitlab添加

image-20220416212417100

3.添加私钥到ssh-agent中

添加私钥到ssh-agent中 ,出现Identity added表示成功

bash
ssh-add ~/.ssh/id_rsa_github_qq
ssh-add ~/.ssh/id_rsa_github_qq
  1. 若提示 Could not open a connection to your authentication agent

​ 先执行ssh-agent bash 再执行上面代码

  1. 报错: Error connecting to agent: No such file or directory

​ 解决方法:检查文件是否存在,并【以管理员身份运行】在 PowerShell 执行

bash
Set-Service ssh-agent -StartupType Manual
+Start-Service ssh-agent
Set-Service ssh-agent -StartupType Manual
+Start-Service ssh-agent
  1. 报错 unable to start ssh-agent service, error :1058

​ 以【管理员身份】打开终端,执行Set-Service -Name ssh-agent -StartupType automatic

  • 查看私钥列表
bash
ssh-add -l
ssh-add -l

出现此提示表示未配置成功,重新检查步骤配置

bash
git@github.com: Permission denied (publickey).
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
git@github.com: Permission denied (publickey).
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.

4.创建config件,打开编辑

注意:文件名就是config,没有文件后缀,编辑完保存前记得去掉注释

bash
Host github.com #github主机地址
+HostName github.com #github主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_github #私钥地址
+
+Host gitlab.xxx.cn  #公司gitlab主机地址
+HostName gitlab.xxx.cn	#gitlab主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_gitlab	#私钥地址
Host github.com #github主机地址
+HostName github.com #github主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_github #私钥地址
+
+Host gitlab.xxx.cn  #公司gitlab主机地址
+HostName gitlab.xxx.cn	#gitlab主机名
+PreferredAuthentications publickey
+IdentityFile ~/.ssh/id_rsa_gitlab	#私钥地址
  • 测试连接是否成功,显示出这句话表示成功啦,可以看到自己账户名

    Hi CoderFXJ! You've successfully authenticated, but GitHub does not provide shell access.

    bash
    ssh -T git@gitee.com
    +#或
    +ssh -T git@github.com
    +
    +ssh -T git@gitlab.xxx.cn
    ssh -T git@gitee.com
    +#或
    +ssh -T git@github.com
    +
    +ssh -T git@gitlab.xxx.cn

SSH公钥私钥加密解密原理

`,27),e=[p];function t(c,r,i,y,A,d){return a(),n("div",null,e)}const g=s(o,[["render",t]]);export{h as __pageData,g as default}; diff --git "a/assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.lean.js" "b/assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.lean.js" new file mode 100644 index 00000000..e7647d80 --- /dev/null +++ "b/assets/FrontEnd_Git_\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md.49289c60.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Git/配置多个平台SSH.md","filePath":"FrontEnd/Git/配置多个平台SSH.md"}'),o={name:"FrontEnd/Git/配置多个平台SSH.md"},p=l("",27),e=[p];function t(c,r,i,y,A,d){return a(),n("div",null,e)}const g=s(o,[["render",t]]);export{h as __pageData,g as default}; diff --git "a/assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.js" "b/assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.js" new file mode 100644 index 00000000..687154e0 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.js" @@ -0,0 +1,197 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"Javascript实现异步","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/async与await.md","filePath":"FrontEnd/JavaScript/async与await.md"}'),p={name:"FrontEnd/JavaScript/async与await.md"},o=l(`

Javascript实现异步

INFO

Javascript是单线程执行语言

方式一:回调函数

js
let timer = setTimeout(()=>{
+    console.log("3秒后打印的")
+},3000)
+console.log("比setTimeout回调函数先执行")
+//本身会立刻返回,然后执行后面同步代码,回调函数则等预定时间才执行
let timer = setTimeout(()=>{
+    console.log("3秒后打印的")
+},3000)
+console.log("比setTimeout回调函数先执行")
+//本身会立刻返回,然后执行后面同步代码,回调函数则等预定时间才执行

缺点:容易形成回调地狱

js
setTimeout(()=>{
+    console.log("3秒后打印的")
+    
+   setTimeout(()=>{    
+       console.log("6秒后打印的")
+       
+         setTimeout(
+            ()=>{    
+               console.log("9秒后打印的")
+         },3000)
+   },3000)
+},3000)
setTimeout(()=>{
+    console.log("3秒后打印的")
+    
+   setTimeout(()=>{    
+       console.log("6秒后打印的")
+       
+         setTimeout(
+            ()=>{    
+               console.log("9秒后打印的")
+         },3000)
+   },3000)
+},3000)

方式二:Promise

声名Promise

new Promise(function(resolve, reject){ })

js
new Promise(function(resolve, reject) { 
+    resolve('success')  // 成功执行
+}).then(result => {
+    alert(result)  //走then
+}).finally(()=>{
+	//无论成功失败,都会执行的回调
+    //做一些清理工作,如关闭加载动画
+})
+
+new Promise(function(resolve, reject) { 
+    reject('fail')  // 失败执行
+}).then(result => {
+    alert(result)
+}).catch(error => {
+     alert(error)  //走catch
+})
new Promise(function(resolve, reject) { 
+    resolve('success')  // 成功执行
+}).then(result => {
+    alert(result)  //走then
+}).finally(()=>{
+	//无论成功失败,都会执行的回调
+    //做一些清理工作,如关闭加载动画
+})
+
+new Promise(function(resolve, reject) { 
+    reject('fail')  // 失败执行
+}).then(result => {
+    alert(result)
+}).catch(error => {
+     alert(error)  //走catch
+})

如果想终止在某个执行链的位置,可以用Promise.reject(new Error())

js
new Promise(function(resolve, reject) {
+    resolve(1)
+}).then(result => {
+    return result + 1
+}).then(result => {
+    return result + 1
+}).then(result => {
+    
+  return  Promise.reject(new Error(result + '失败'))
+   // return result + 1
+}).then(result => {
+    return result + 1
+}).catch(error => {	
+    alert(error)
+})
new Promise(function(resolve, reject) {
+    resolve(1)
+}).then(result => {
+    return result + 1
+}).then(result => {
+    return result + 1
+}).then(result => {
+    
+  return  Promise.reject(new Error(result + '失败'))
+   // return result + 1
+}).then(result => {
+    return result + 1
+}).catch(error => {	
+    alert(error)
+})

语法糖:async /await

await 表示强制等待的意思,await关键字的后面要跟一个promise对象,它总是等到该promise对象resolve成功之后执行,并且会返回resolve的结果

async标记该函数就是一个异步函数,不会阻塞其他执行逻辑的执行,被async标记的函数返回也是promise对象

async 和 await必须成对出现,不能用在普通函数上

js
async fn1() {
+ const result = await new Promise(function(resolve){  
+    setTimeout(function(){
+      resolve('fn1执行结果')
+    },5000)
+ })
+ console.log(result)
+},
+    
+fn2(){
+  this.fn1() //async的函数并不会阻塞后续同步代码执行
+  console.log('fn2执行') //先执行
+}
async fn1() {
+ const result = await new Promise(function(resolve){  
+    setTimeout(function(){
+      resolve('fn1执行结果')
+    },5000)
+ })
+ console.log(result)
+},
+    
+fn2(){
+  this.fn1() //async的函数并不会阻塞后续同步代码执行
+  console.log('fn2执行') //先执行
+}

实现fn1先执行

js
 async fn2(){
+     await this.fn1()
+     console.log('fn2执行')
+   }
 async fn2(){
+     await this.fn1()
+     console.log('fn2执行')
+   }

捕获异常

js
   async  getCatch () {
+      try { // 通过 try/catch捕获异常
+        await new Promise(function (resolve, reject) {
+          reject(new Error('失败'))
+        })
+         console.log('log1')
+      } catch (error) {
+         console.log('log2')
+      }
+   }
   async  getCatch () {
+      try { // 通过 try/catch捕获异常
+        await new Promise(function (resolve, reject) {
+          reject(new Error('失败'))
+        })
+         console.log('log1')
+      } catch (error) {
+         console.log('log2')
+      }
+   }

使用陷阱

1.会打破异步操作并行

js
async  fn1(){
+    const a = await fetch("http://.../post/1")
+    const b = await fetch("http://.../post/2")
+    //a任务需要等到b任务执行完后才执行
+}
async  fn1(){
+    const a = await fetch("http://.../post/1")
+    const b = await fetch("http://.../post/2")
+    //a任务需要等到b任务执行完后才执行
+}

高效做法

js
async  fn1(){
+    const promistA =  fetch("http://.../post/1")
+    const promistB =  fetch("http://.../post/2")
+    //利用 Promise.all组合
+    const [a,b] = await Promise.all([promiseA,pormiseB])
+    
+}
async  fn1(){
+    const promistA =  fetch("http://.../post/1")
+    const promistB =  fetch("http://.../post/2")
+    //利用 Promise.all组合
+    const [a,b] = await Promise.all([promiseA,pormiseB])
+    
+}

2.循环中执行异步操作,不能直接使用forEach,map等方法

js
async  fn(){
+    [1,2,3].forEach(await (item)=>{
+        await someAsyncOpt()
+    })//会立刻返回,并不会等待所有异步操作执行完
+    console.log('done')
+}
async  fn(){
+    [1,2,3].forEach(await (item)=>{
+        await someAsyncOpt()
+    })//会立刻返回,并不会等待所有异步操作执行完
+    console.log('done')
+}

解决方法

js
async  fn(){
+   for(let i of  [1,2,3]){
+		await someAsyncOpt()
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}
async  fn(){
+   for(let i of  [1,2,3]){
+		await someAsyncOpt()
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}

高效做法

js
async  fn(){
+    const promises = [
+        someAsyncOpt(),
+        someAsyncOpt(),
+        someAsyncOpt(),
+    ]
+   for await (let res of promises ){
+		//...
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}
async  fn(){
+    const promises = [
+        someAsyncOpt(),
+        someAsyncOpt(),
+        someAsyncOpt(),
+    ]
+   for await (let res of promises ){
+		//...
+   } //等待所有异步操作执行完毕在执行后面代码
+    console.log('done')
+}
`,32),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.lean.js" "b/assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.lean.js" new file mode 100644 index 00000000..2ad33c42 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_async\344\270\216await.md.d21c9cb0.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"Javascript实现异步","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/async与await.md","filePath":"FrontEnd/JavaScript/async与await.md"}'),p={name:"FrontEnd/JavaScript/async与await.md"},o=l("",32),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.js" "b/assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.js" new file mode 100644 index 00000000..9b6f663a --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.js" @@ -0,0 +1,117 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"if else 多分支优化","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/代码分支优化.md","filePath":"FrontEnd/JavaScript/代码分支优化.md"}'),p={name:"FrontEnd/JavaScript/代码分支优化.md"},o=l(`

if else 多分支优化

简单分支

js
//优化前
+function speak(name){
+  if(name==='老牛'){
+    console.log('老牛哞哞叫')
+  }else if(name==='老虎'){
+    console.log('老牛嗷嗷叫')
+  }else if(name==='老鸡'){
+    console.log('老牛咯咯叫')
+  }
+}
+
+//优化后
+function speak(name){
+   const map = {
+    老牛:'老牛哞哞叫',
+    老虎:'老虎嗷嗷叫',
+    老鸡:'老鸡咯咯叫'
+   }
+  if(map[name]){
+    console.log(map[name])
+  }else {
+    console.log('不知道怎么叫')
+  }
+}
+
+speak('老牛')
//优化前
+function speak(name){
+  if(name==='老牛'){
+    console.log('老牛哞哞叫')
+  }else if(name==='老虎'){
+    console.log('老牛嗷嗷叫')
+  }else if(name==='老鸡'){
+    console.log('老牛咯咯叫')
+  }
+}
+
+//优化后
+function speak(name){
+   const map = {
+    老牛:'老牛哞哞叫',
+    老虎:'老虎嗷嗷叫',
+    老鸡:'老鸡咯咯叫'
+   }
+  if(map[name]){
+    console.log(map[name])
+  }else {
+    console.log('不知道怎么叫')
+  }
+}
+
+speak('老牛')

条件单一,处理不同

js
function speak(name){
+   const map = {
+    老牛:() =>  { ... },
+    老虎:() =>  { ... },
+    老鸡:() =>  { ... }
+   }
+  if(map[name]){
+     map[name]()
+  }else {
+    console.log('xxx')
+  }
+}
function speak(name){
+   const map = {
+    老牛:() =>  { ... },
+    老虎:() =>  { ... },
+    老鸡:() =>  { ... }
+   }
+  if(map[name]){
+     map[name]()
+  }else {
+    console.log('xxx')
+  }
+}

条件复杂,处理也复杂

js
function speak(name){
+   const arr = [  //条件,处理映射
+    [
+      () =>  { ... },//条件1
+      () =>  { ... } //处理函数1
+    ],
+    [
+      () =>  { ... },//条件2
+      () =>  { ... } //处理函数2
+    ],
+    [
+      () =>  { ... },//条件3
+      () =>  { ... } //处理函数4
+    ],
+   ]
+
+  const target = arr.find(item => item[0]())
+  if(target){
+     target[1]()
+  }else {
+    console.log('xxx')
+  }
+}
function speak(name){
+   const arr = [  //条件,处理映射
+    [
+      () =>  { ... },//条件1
+      () =>  { ... } //处理函数1
+    ],
+    [
+      () =>  { ... },//条件2
+      () =>  { ... } //处理函数2
+    ],
+    [
+      () =>  { ... },//条件3
+      () =>  { ... } //处理函数4
+    ],
+   ]
+
+  const target = arr.find(item => item[0]())
+  if(target){
+     target[1]()
+  }else {
+    console.log('xxx')
+  }
+}
`,7),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.lean.js" "b/assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.lean.js" new file mode 100644 index 00000000..764ccca5 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\344\273\243\347\240\201\345\210\206\346\224\257\344\274\230\345\214\226.md.e8fda00c.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"if else 多分支优化","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/代码分支优化.md","filePath":"FrontEnd/JavaScript/代码分支优化.md"}'),p={name:"FrontEnd/JavaScript/代码分支优化.md"},o=l("",7),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.js" "b/assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.js" new file mode 100644 index 00000000..03216a57 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.js" @@ -0,0 +1,51 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"JS 图片懒加载","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/图片懒加载.md","filePath":"FrontEnd/JavaScript/图片懒加载.md"}'),p={name:"FrontEnd/JavaScript/图片懒加载.md"},o=l(`

JS 图片懒加载

方案一:监听滚动

TIP

监听图片顶部到达视口底部,把自定义属性 data-src赋值给src

js
const images = document.querySelectorAll('img')
+window.addEventListener('scroll', (e) => {
+    images.forEach(
+        image => {
+            const imageTop = image.getBoundingClientRect().top
+            if (imageTop < window.innerHeight) {
+                const data_src = image.getAttribute('data-src')
+                image.setAttribute('src', data_src)
+            }
+        }
+    )
+})
const images = document.querySelectorAll('img')
+window.addEventListener('scroll', (e) => {
+    images.forEach(
+        image => {
+            const imageTop = image.getBoundingClientRect().top
+            if (imageTop < window.innerHeight) {
+                const data_src = image.getAttribute('data-src')
+                image.setAttribute('src', data_src)
+            }
+        }
+    )
+})

方案二:观察者

js
const images = document.querySelectorAll('img')
+const callback = enteries => {
+    enteries.forEach(entry => {
+        if (entry.isIntersecting) {
+            const img = entry.target
+            const data_src = img.getAttribute('data-src')
+            img.setAttribute('src', data_src)
+            observer.unobserve(img)
+        }
+    });
+}
+const observer = new IntersectionObserver(callback)
+images.forEach(image => {
+    observer.observe(image)
+})
const images = document.querySelectorAll('img')
+const callback = enteries => {
+    enteries.forEach(entry => {
+        if (entry.isIntersecting) {
+            const img = entry.target
+            const data_src = img.getAttribute('data-src')
+            img.setAttribute('src', data_src)
+            observer.unobserve(img)
+        }
+    });
+}
+const observer = new IntersectionObserver(callback)
+images.forEach(image => {
+    observer.observe(image)
+})
`,6),e=[o];function t(c,r,y,A,D,i){return a(),n("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.lean.js" "b/assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.lean.js" new file mode 100644 index 00000000..911d6052 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\233\276\347\211\207\346\207\222\345\212\240\350\275\275.md.3d5465d0.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"JS 图片懒加载","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/图片懒加载.md","filePath":"FrontEnd/JavaScript/图片懒加载.md"}'),p={name:"FrontEnd/JavaScript/图片懒加载.md"},o=l("",6),e=[o];function t(c,r,y,A,D,i){return a(),n("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.js" "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.js" new file mode 100644 index 00000000..f5605b0b --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.js" @@ -0,0 +1,113 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/基础复习一.md","filePath":"FrontEnd/JavaScript/基础复习一.md"}'),p={name:"FrontEnd/JavaScript/基础复习一.md"},o=l(`

1.算术运算符

隐式类型转换

除了加法和其他字符串运算时,它先将其他值转为字符串,在进行拼接;其他运算它先将其他值转为数字,在进行运算

js
a = 10 - '5' //5
+a = 10 - true // 9
+a = 10 - false //10
+a = 10 - undefined // NaN
+a = 10 - null // 10
a = 10 - '5' //5
+a = 10 - true // 9
+a = 10 - false //10
+a = 10 - undefined // NaN
+a = 10 - null // 10

2.赋值运算符

js
let a = 10
+a = a + 10 // a += 10  (*= 	/=   %=		**=)
+//	??= 只有当a为undefined或null才会进行赋值
let a = 10
+a = a + 10 // a += 10  (*= 	/=   %=		**=)
+//	??= 只有当a为undefined或null才会进行赋值

3..运算符

js
+'123' // 123
+a = 123
+b = -a //-123
+'123' // 123
+a = 123
+b = -a //-123

4.自增和自减

js
//	++ 使用后回事原来的变量立刻增加1
+a++
+a--
+
+//前自增:返回自增前的值
+//后自增:返回自增后的值
//	++ 使用后回事原来的变量立刻增加1
+a++
+a--
+
+//前自增:返回自增前的值
+//后自增:返回自增后的值

5.逻辑运算符

js
!   //逻辑非:对布尔值值取反,对非布尔值值取反,会先将其转为布尔值值再取反,可运用于隐式转布尔值   !!123 -> true
+    
+&&  //逻辑与:左右都为true返回true,否则返回false;非布尔值运算,会先转为布尔值后运算,但是最终返回原值
+    	//-	第一个值为(falsy),则直接返回第一个值的原值1,如果第一个值为ture,则直接返回第二个值
+    	NaN && 2	-> NaN
+		0 && 1 		-> 0
+
+        1 && undefined	->	undefined
+        1 && false 		->	false
+
+||  //逻辑或:左右有true,则不看第二个值,则返回true的原值,否则返回false 	
+      	12 || false		->	 12	
+		null || {a : 1}	->	 {a : 1}
!   //逻辑非:对布尔值值取反,对非布尔值值取反,会先将其转为布尔值值再取反,可运用于隐式转布尔值   !!123 -> true
+    
+&&  //逻辑与:左右都为true返回true,否则返回false;非布尔值运算,会先转为布尔值后运算,但是最终返回原值
+    	//-	第一个值为(falsy),则直接返回第一个值的原值1,如果第一个值为ture,则直接返回第二个值
+    	NaN && 2	-> NaN
+		0 && 1 		-> 0
+
+        1 && undefined	->	undefined
+        1 && false 		->	false
+
+||  //逻辑或:左右有true,则不看第二个值,则返回true的原值,否则返回false 	
+      	12 || false		->	 12	
+		null || {a : 1}	->	 {a : 1}

6.关系运算符

js
//用来检查两个值的关系是否成立,成立返回true,否则返回false (多个比较用&&)
+	>	>=	<	<=
+// 非数值与数值比较会先非数值转为数值再比较  7 < '10' ->  true
+//	两端为字符串则逐个比较字符的Unicode编码	 
+   'a' > 'b' -> false		
+   'abc' < 'b' -> true(比完第一位则结束)
+   '12' < '2'	-> true
//用来检查两个值的关系是否成立,成立返回true,否则返回false (多个比较用&&)
+	>	>=	<	<=
+// 非数值与数值比较会先非数值转为数值再比较  7 < '10' ->  true
+//	两端为字符串则逐个比较字符的Unicode编码	 
+   'a' > 'b' -> false		
+   'abc' < 'b' -> true(比完第一位则结束)
+   '12' < '2'	-> true

7.相等运算符

js
==/!=	//用来比较两个值是否相等/不相等,不同类型会转为相同类型再比较	
+    '2' == 2	-> true
+	//null和undefined进行相等比较会返回true(null == undefined -> true)
+	//NaN不和任何值相等,包括它自身
+===/!== //检查两个值是否全等/不全等,不会自动类型转换
+    '2' == 2	-> false
+	//null === undefined -> false
==/!=	//用来比较两个值是否相等/不相等,不同类型会转为相同类型再比较	
+    '2' == 2	-> true
+	//null和undefined进行相等比较会返回true(null == undefined -> true)
+	//NaN不和任何值相等,包括它自身
+===/!== //检查两个值是否全等/不全等,不会自动类型转换
+    '2' == 2	-> false
+	//null === undefined -> false

8.条件运算符

js
表达式 ? 表达式1 : 表达式2	//let max = a > b ? a : b
表达式 ? 表达式1 : 表达式2	//let max = a > b ? a : b

9.控制语句

js
if{	}else if(){	}else{	}
+if //不加{}if只会控制紧随其后的一条语句
+ 
+switch(表达式){
+    case 表达式:
+        break
+        ...
+    default
+        ...
+        //表达式进行全等比较,满足则执行代码,否则比较其他case后的表达式
+}
if{	}else if(){	}else{	}
+if //不加{}if只会控制紧随其后的一条语句
+ 
+switch(表达式){
+    case 表达式:
+        break
+        ...
+    default
+        ...
+        //表达式进行全等比较,满足则执行代码,否则比较其他case后的表达式
+}

10.循环语句

js
//循环三要素 1.初始化变量	2.条件表达式	3.更新表达式
+while(条件表达式){...}
+do{	...	}while(表达式)	//先执行一次循环体,再判断条件是否执行循环体
+for(let i = 0;i < 10;i++){ ... } //for(;;)死循环
//循环三要素 1.初始化变量	2.条件表达式	3.更新表达式
+while(条件表达式){...}
+do{	...	}while(表达式)	//先执行一次循环体,再判断条件是否执行循环体
+for(let i = 0;i < 10;i++){ ... } //for(;;)死循环

break与continue💔终止离它最近的循环, break立即循环停止; continue跳过当前循环,继续下一次循环

11.数据类型

js
//原始值(7种):
+	Number,String,Boolean,Null,Undefined,BigInt,Symbol
+//引用值(对象)
+	Object
+    {
+        [Symbol()]:'此值不可枚举'
+    }
//原始值(7种):
+	Number,String,Boolean,Null,Undefined,BigInt,Symbol
+//引用值(对象)
+	Object
+    {
+        [Symbol()]:'此值不可枚举'
+    }
`,25),e=[o];function t(c,r,y,A,D,i){return a(),n("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.lean.js" "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.lean.js" new file mode 100644 index 00000000..f1a19dc7 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\270\200.md.a8906ce7.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/基础复习一.md","filePath":"FrontEnd/JavaScript/基础复习一.md"}'),p={name:"FrontEnd/JavaScript/基础复习一.md"},o=l("",25),e=[o];function t(c,r,y,A,D,i){return a(),n("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.js" "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.js" new file mode 100644 index 00000000..f9392f77 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.js" @@ -0,0 +1,415 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/基础复习二.md","filePath":"FrontEnd/JavaScript/基础复习二.md"}'),p={name:"FrontEnd/JavaScript/基础复习二.md"},o=l(`

this指向

根据函数调用方式的不同,this的值也不同:

TIP

  1. 以函数形式调用,this是window
  2. 以方法形式调用, this是调用方法的对象
  3. 构造函数中,this是新建的对象
  4. 箭头函数没有自己的this, 由外层作用域决定
  5. 通过call和apply调用的函数,它们的第一个参数就是函数的this
  6. 通过bind返回的函数,this由bind第一个参数决定(无法修改)
js
function fn(){
+	console.log(this)//window
+}
+let obj = {
+	name:'zhansan',
+    fn(){
+		console.log(this)//obj
+        function fn2(){
+            console.log(this) //window     
+        }
+        fn3 = ()=> {
+            console.log(this)//obj,与调用方式无关,指向声明时外层作用域的this
+        }
+        fn2()//以函数形式调用指向window
+    }
+}
+obj.fn()//以方法形式调用,指向obj
function fn(){
+	console.log(this)//window
+}
+let obj = {
+	name:'zhansan',
+    fn(){
+		console.log(this)//obj
+        function fn2(){
+            console.log(this) //window     
+        }
+        fn3 = ()=> {
+            console.log(this)//obj,与调用方式无关,指向声明时外层作用域的this
+        }
+        fn2()//以函数形式调用指向window
+    }
+}
+obj.fn()//以方法形式调用,指向obj

函数三种调用方式

js
fn()
+fn.call()
+fn.apply()
fn()
+fn.call()
+fn.apply()

call和bind与apply

  1. call 和 apply除了可以调用函数,还可以用来指定函数中的this

    • 通过call方法调用函数,函数的实参直接在第一个参数后一个一个的列出来
    • apply 实参需要通过一个数组传递
  2. bind() 是函数的方法,可以用来创建一个新的函数

    • bind可以为新函数绑定this
    • bind可以为新函数绑定参数
js
fn2.call(obj, "hello", true)//会立即执行
+fn2.apply(obj, ["hello", true]//会立即执行
+let newfn = fn.bind(obj, 10, 20, 30)//不会立即执行, 返回一个新函数 	newfn()
fn2.call(obj, "hello", true)//会立即执行
+fn2.apply(obj, ["hello", true]//会立即执行
+let newfn = fn.bind(obj, 10, 20, 30)//不会立即执行, 返回一个新函数 	newfn()

箭头函数没有自身的this,它的this由定义时外层作用域决定,

  • 也无法通过call apply 和 bind修改它的this

  • 箭头函数中没有arguments

可变参数 arguments

js
 // 定义一个函数,可以求任意个数值的和
+function sum() {
+// 通过arguments,可以不受参数数量的限制更加灵活的创建函数
+ /* arguments
+    - arguments是函数中又一个隐含参数
+    - arguments是一个类数组对象(伪数组)
+        和数组相似,可以通过索引来读取元素,也可以通过for循环变量,							
+        但是它不是一个数组对象,不能调用数组的方法
+    - arguments用来存储函数的实参,
+        无论用户是否定义形参,实参都会存储到arguments对象中
+        可以通过该对象直接访问实参*/
+    let result = 0
+
+    for (let num of arguments) {
+        result += num
+    }
+
+    return result
+}
 // 定义一个函数,可以求任意个数值的和
+function sum() {
+// 通过arguments,可以不受参数数量的限制更加灵活的创建函数
+ /* arguments
+    - arguments是函数中又一个隐含参数
+    - arguments是一个类数组对象(伪数组)
+        和数组相似,可以通过索引来读取元素,也可以通过for循环变量,							
+        但是它不是一个数组对象,不能调用数组的方法
+    - arguments用来存储函数的实参,
+        无论用户是否定义形参,实参都会存储到arguments对象中
+        可以通过该对象直接访问实参*/
+    let result = 0
+
+    for (let num of arguments) {
+        result += num
+    }
+
+    return result
+}

剩余参数 ...args

js
 function sum2(...num) {
+ /* 
+剩余参数,在定义函数时可以将参数指定为剩余参数
+- 剩余参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
+- 作用和arguments基本是一致,但是也具有一些不同点:
+    是一个数组,名字可以自己指定,配合其他参数一起使用,剩余参数写到最后。
+ */
+    return num.reduce((a, b) => a + b, 0)
+ }
+function fn3(a, b, ...args) {
+  console.log(args)
+ }
 function sum2(...num) {
+ /* 
+剩余参数,在定义函数时可以将参数指定为剩余参数
+- 剩余参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
+- 作用和arguments基本是一致,但是也具有一些不同点:
+    是一个数组,名字可以自己指定,配合其他参数一起使用,剩余参数写到最后。
+ */
+    return num.reduce((a, b) => a + b, 0)
+ }
+function fn3(a, b, ...args) {
+  console.log(args)
+ }

Map

  • Map用来存储键值对结构的数据(key-value)
  • Object中存储的数据就可以认为是一种键值对结构
  • Map和Object的主要区别:
    • Object中的属性名只能是字符串或符号,如果传递了一个其他类型的属性名, JS解释器会自动将其转换为字符串
    • Map中任何类型的值都可以称为数据的key
js
/*属性和方法:
+  map.size() 获取map中键值对的数量
+  map.set(key, value) 向map中添加键值对
+  map.get(key) 根据key获取值   
+  map.delete(key) 删除指定数据
+  map.has(key) 检查map中是否包含指定键
+  map.clear() 删除全部的键值对*/
+    
+    const obj = {
+        "name":"孙悟空",
+        'age':18,
+        [Symbol()]:"哈哈",
+        [obj2]:"嘻嘻"
+    }
/*属性和方法:
+  map.size() 获取map中键值对的数量
+  map.set(key, value) 向map中添加键值对
+  map.get(key) 根据key获取值   
+  map.delete(key) 删除指定数据
+  map.has(key) 检查map中是否包含指定键
+  map.clear() 删除全部的键值对*/
+    
+    const obj = {
+        "name":"孙悟空",
+        'age':18,
+        [Symbol()]:"哈哈",
+        [obj2]:"嘻嘻"
+    }

将map转换为数组

js
const arr = Array.from(map)//const arr = [...map]
+ // 遍历map
+  for (const [key, value] of map) {
+     const [key, value] = entry
+    console.log(key, value)
+   }
+
+    map.forEach((key, value)=>{
+        console.log(key, value)
+    })
+
+ map.keys() - 获取map的所有的key
+ map.values() - 获取map的所有的value
const arr = Array.from(map)//const arr = [...map]
+ // 遍历map
+  for (const [key, value] of map) {
+     const [key, value] = entry
+    console.log(key, value)
+   }
+
+    map.forEach((key, value)=>{
+        console.log(key, value)
+    })
+
+ map.keys() - 获取map的所有的key
+ map.values() - 获取map的所有的value

数组转map

js
const map2 = new Map([
+    ["name", "猪八戒"],
+    ["age", 18],
+    [{}, () => {}],
+])
const map2 = new Map([
+    ["name", "猪八戒"],
+    ["age", 18],
+    [{}, () => {}],
+])

Set

js
/* - 使用方式:
+    创建
+        - new Set()
+        - new Set([...])
+
+    方法
+        size 获取数量
+        add() 添加元素
+        has() 检查元素
+        delete() 删除元素
+        [...set]转为数组获取元素 
+        set.entries() 得到键值对(键值对一样)
+        */
/* - 使用方式:
+    创建
+        - new Set()
+        - new Set([...])
+
+    方法
+        size 获取数量
+        add() 添加元素
+        has() 检查元素
+        delete() 删除元素
+        [...set]转为数组获取元素 
+        set.entries() 得到键值对(键值对一样)
+        */

随机数生成

js
 Math.random() --> 0 - 1
+//生成 0-x之间的随机数:
+Math.round(Math.random() * x)
+Math.floor(Math.random() * (x + 1))
+
+//生成 x-y 之间的随机数
+Math.round(Math.random() * (y-x) + x)
 Math.random() --> 0 - 1
+//生成 0-x之间的随机数:
+Math.round(Math.random() * x)
+Math.floor(Math.random() * (x + 1))
+
+//生成 x-y 之间的随机数
+Math.round(Math.random() * (y-x) + x)

时间格式化

js
const d = new Date()
+
+let result = d.toLocaleDateString() // 将日期转换为本地的字符串		'2021/10/1
+result = d.toLocaleTimeString() // 将时间转换为本地的字符串 	'21:32:35'
+/*   - 参数:
+1. locales: 描述语言和国家信息的字符串
+    zh-CN 中文中国
+    zh-HK 中文香港
+    en-US 英文美国
+2. options: 需要一个对象作为参数,在对象中可以通过对象的属性来对日期的格式进行配置
+*/
+  result = d.toLocaleString("zh-CN", {
+    year: "numeric",
+    month: "long",
+    day: "2-digit",
+    weekday: "short",
+    hour: "2-digit",
+    minute: "2-digit"
+})
const d = new Date()
+
+let result = d.toLocaleDateString() // 将日期转换为本地的字符串		'2021/10/1
+result = d.toLocaleTimeString() // 将时间转换为本地的字符串 	'21:32:35'
+/*   - 参数:
+1. locales: 描述语言和国家信息的字符串
+    zh-CN 中文中国
+    zh-HK 中文香港
+    en-US 英文美国
+2. options: 需要一个对象作为参数,在对象中可以通过对象的属性来对日期的格式进行配置
+*/
+  result = d.toLocaleString("zh-CN", {
+    year: "numeric",
+    month: "long",
+    day: "2-digit",
+    weekday: "short",
+    hour: "2-digit",
+    minute: "2-digit"
+})

面向对象之类

js
 class Person{
+	 constructor(name, age, gender){
+        // console.log("构造函数执行了~", name, age, gender)
+        // 可以在构造函数中,为实例属性进行赋值
+        // 在构造函数中,this表示当前所创建的对象
+        this.name = name
+        this.age = age
+        this.gender = gender
+
+    }
+
+    // sayHello = function(){} // 添加方法的一种方式
+
+    sayHello(){
+        console.log('大家好,我是' + this.name)
+    } // 添加方法(实例方法) 实例方法中this就是当前实例
+
+    static test(){
+        console.log("我是静态方法", this)
+    } // 静态方法(类方法) 通过类来调用 静态方法中this指向的是当前类
+
+}
 class Person{
+	 constructor(name, age, gender){
+        // console.log("构造函数执行了~", name, age, gender)
+        // 可以在构造函数中,为实例属性进行赋值
+        // 在构造函数中,this表示当前所创建的对象
+        this.name = name
+        this.age = age
+        this.gender = gender
+
+    }
+
+    // sayHello = function(){} // 添加方法的一种方式
+
+    sayHello(){
+        console.log('大家好,我是' + this.name)
+    } // 添加方法(实例方法) 实例方法中this就是当前实例
+
+    static test(){
+        console.log("我是静态方法", this)
+    } // 静态方法(类方法) 通过类来调用 静态方法中this指向的是当前类
+
+}

面向对象的特点:封装、继承和多态

封装 —— 安全性 继承 —— 扩展性 多态 —— 灵活性

封装

TIP

  1. 对象就是一个用来存储不同属性的容器
  2. 对象不仅存储属性,还要负责数据的安全, 直接添加到对象中的属性,并不安全,因为它们可以被任意的修改
  3. 如何确保数据的安全:
    • 私有化数据: 将需要保护的数据设置为私有,只能在类内部使用
    • 提供setter和getter方法来开放对数据的操作
    • 属性设置私有,通过getter setter方法操作属性带来的好处
      1. 可以控制属性的读写权限
      2. 可以在方法中对属性的值进行验证
js
 - 实现封装的方式
+    1.属性私有化 #
+    2.通过getter和setter方法来操作属性
+        get 属性名(){
+            return this.#属性
+        }
+
+        set 属性名(参数){
+            this.#属性 = 参数
+        }
 - 实现封装的方式
+    1.属性私有化 #
+    2.通过getter和setter方法来操作属性
+        get 属性名(){
+            return this.#属性
+        }
+
+        set 属性名(参数){
+            this.#属性 = 参数
+        }
js
 class Person {
+	 #name//实例使用#开头就变成了私有属性,私有属性只能在类内部访问
+        constructor(name, age, gender) {
+            this.#name = name
+        }
+
+        sayHello() {
+            console.log(this.#name)
+        }
+ 
+        getName(){// getter方法,用p.getName()来读取属性
+            return this.#name
+        }
+
+        // setter方法,用来设置属性,p.setName('zhangsan')
+        setName(name){
+            this.#name = name
+        }
+
+        get name(){//简化读取方式:p.name
+            return this.#name
+        }
+
+        set name(gender){
+            this.#name = name
+        }
+    }
 class Person {
+	 #name//实例使用#开头就变成了私有属性,私有属性只能在类内部访问
+        constructor(name, age, gender) {
+            this.#name = name
+        }
+
+        sayHello() {
+            console.log(this.#name)
+        }
+ 
+        getName(){// getter方法,用p.getName()来读取属性
+            return this.#name
+        }
+
+        // setter方法,用来设置属性,p.setName('zhangsan')
+        setName(name){
+            this.#name = name
+        }
+
+        get name(){//简化读取方式:p.name
+            return this.#name
+        }
+
+        set name(gender){
+            this.#name = name
+        }
+    }

继承

继承

  • 可以通过extends关键来完成继承 时,就相当于将另一个类中的代码复制到了当前类中(简单理解)
  • 继承发生时,被继承的类称为 父类(超类),继承的类称为 子类 的代码,并且可以在不修改一个类的前提对其进行扩展
js
 class Animal{
+    constructor(name){
+        this.name = name
+    }
+    sayHello(){
+        console.log("动物在叫~")
+    }
+}
+
+class Dog extends Animal{
+    // 重写构造函数
+    constructor(name, age){
+        // 重写构造函数时,构造函数的第一行代码必须为super()
+        super(name) // 调用父类的构造函数
+        this.age = age
+
+    }
+	// 在子类中,可以通过创建同名方法来重写父类的方法
+    sayHello(){
+        console.log("汪汪汪")
+    }
+}
+const dog = new Dog("旺财")
+dog.sayHello()
 class Animal{
+    constructor(name){
+        this.name = name
+    }
+    sayHello(){
+        console.log("动物在叫~")
+    }
+}
+
+class Dog extends Animal{
+    // 重写构造函数
+    constructor(name, age){
+        // 重写构造函数时,构造函数的第一行代码必须为super()
+        super(name) // 调用父类的构造函数
+        this.age = age
+
+    }
+	// 在子类中,可以通过创建同名方法来重写父类的方法
+    sayHello(){
+        console.log("汪汪汪")
+    }
+}
+const dog = new Dog("旺财")
+dog.sayHello()

多态

在JS中不会检查参数的类型,所以这就意味着任何数据都可以作为参数传递 指定的类型,只要对象满足某些条件即可

js
function sayHello(obj){
+ console.log("Hello,"+obj.name)
+}
+//只要参数有obj.name就可以调用
+sayHello(dog)
+sayHello(person)
function sayHello(obj){
+ console.log("Hello,"+obj.name)
+}
+//只要参数有obj.name就可以调用
+sayHello(dog)
+sayHello(person)

对象的结构

原型

对象中存储属性的区域实际有两个:

TIP

  1. 对象自身

    • 直接通过对象所添加的属性,位于对象自身中
    • 中通过 x = y 的形式添加的属性,位于对象自身中
  2. 原型对象(prototype)

    • 对象中还有一些内容,会存储到其他的对象里(原型对象)
    • 在对象中会有一个属性用来存储原型对象,这个属性叫做__proto__
    • 原型对象也负责为对象存储属性,
      当我们访问对象中的属性时,会优先访问对象自身的属性,
      对象自身不包含该属性时,才会去原型对象中寻找
    • 会添加到原型对象中的情况:
      1. 在类中通过xxx(){}方式添加的方法,位于原型中
      2. 主动向原型中添加的属性或方法
  3. 访问一个对象的原型对象

    • obj.__proto__
    • Object.getPrototypeOf(对象)
  4. 原型对象中的数据:

    • 对象中的数据(属性、方法等)
    • constructor (对象的构造函数)

原型链: 原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同 obj对象的原型链:obj对象 --> 原型 --> null

原型链

原型链属性查找规则

  1. 读取对象属性时,会优先对象自身属性,
  2. 如果对象中有,则使用,没有则去对象的原型中寻找
  3. 如果原型中有,则使用,没有则去原型的原型中寻找
  4. 直到找到Object对象的原型(Object的原型没有原型(为null))
  5. 如果依然没有找到,则返回undefined

原型的作用:

  1. 原型就相当于是一个公共的区域,可以被所有该类实例访问,
  2. 可以将该类实例中,所有的公共属性(方法)统一存储到原型中
  3. 这样我们只需要创建一个属性,即可被所有实例访问
  4. 一修改就是修改所有实例的原型
  5. 无需创建实例即可完成对类的修改

修改原型

原则

  1. 原型尽量不要手动改
  2. 要改也不要通过实例对象去改
  3. 通过 类.prototype 属性去修改
  4. 最好不要直接给prototype去赋值
js
 Person.prototype.fly = () => {	//在原型添加方法
+    console.log("我在飞!")
+}
 Person.prototype.fly = () => {	//在原型添加方法
+    console.log("我在飞!")
+}

instanceof/in/hasOwn

用于检查的是对象的原型链上是否有该类 dog instanceof Animal

检查对象属性

  • in:使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true
  • 对象.hasOwnProperty(属性名):用来检查一个对象的 自身 是否含有某个属性
  • Object.hasOwn(对象, 属性名):用来检查一个对象的 自身 是否含有某个属性

10.new运算符

new运算符是创建对象时,将会发生这4件事:

  1. 创建一个普通的JS对象(Object对象 {}), 称其为新对象

  2. 将构造函数的prototype属性设置为新对象的原型

  3. 使用实参来执行构造函数,并且将新对象设置为函数中的this

  4. 如果构造函数返回的是一个非原始值,则该值会作为new运算的返回值返回

    如果构造函数的返回值是一个原始值或者没有指定返回值(undefined)

    新的对象将会作为返回值返回(通常不会为构造函数指定返回值)

js
function MyClass(){
+
+     // let newInstance = {}
+     // newInstance.__proto__ = MyClass.prototype
+     // this = newInstance
+     // return newInstance
+
+     }
function MyClass(){
+
+     // let newInstance = {}
+     // newInstance.__proto__ = MyClass.prototype
+     // this = newInstance
+     // return newInstance
+
+     }

对象的分类

  1. 内建对象: 由ES标准所定义的对象
  2. 宿主对象: 由浏览器提供的对象
  3. 自定义对象: 由开发人员自己创建的对象(Vue, React)
`,59),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.lean.js" "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.lean.js" new file mode 100644 index 00000000..a3ce837b --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md.8f89af07.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/基础复习二.md","filePath":"FrontEnd/JavaScript/基础复习二.md"}'),p={name:"FrontEnd/JavaScript/基础复习二.md"},o=l("",59),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.js" "b/assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.js" new file mode 100644 index 00000000..3c20cea6 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.js" @@ -0,0 +1,1683 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/常见算法.md","filePath":"FrontEnd/JavaScript/常见算法.md"}'),p={name:"FrontEnd/JavaScript/常见算法.md"},o=l(`

括号匹配

js
let str1 = '{[]}'	//true
+let str2 = '{[[]}'	//false
+let str3 = '{[]}['	//false
+let str4 = '{[()]}'	//true
let str1 = '{[]}'	//true
+let str2 = '{[[]}'	//false
+let str3 = '{[]}['	//false
+let str4 = '{[()]}'	//true

解决方案:

js
//方案一:
+const isValid = function(str) {
+  	if (str.length == 0) return false
+  	let arr = []
+    let map = {
+        ')': '(',
+        '}': '{',
+        ']': '['
+    }
+    for (let i = 0; i < str.length; i++) {
+        if (str[i] == '(' || str[i] == '{' || str[i] == '[') {
+            arr.push(str[i])
+        } else {
+            //栈顶出栈的左括号 !== map取出右括号匹配的括号类型
+            if (map[str[i]] != arr.pop()) {
+                return false
+            }
+        }
+    }
+    // arr数组已全部匹配,出完栈
+    if (arr.length !== 0) {
+        return false
+    }
+    return true
+}
+
+//方案二:
+function isMatched(str) {
+  let stack = [];
+  let top = -1;
+
+  for (let i = 0; i < str.length; i++) {
+    let ch = str.charAt(i);
+
+    if (ch === '{' || ch === '[' || ch === '(') {
+      stack.push(ch);
+      top++;
+    } else if (ch === '}' && stack[top] === '{') {
+      stack.pop();
+      top--;
+    } else if (ch === ']' && stack[top] === '[') {
+      stack.pop();
+      top--;
+    } else if (ch === ')' && stack[top] === '(') {
+      stack.pop();
+      top--;
+    } else {
+      return false;
+    }
+  }
+
+  return stack.length === 0;
+}
//方案一:
+const isValid = function(str) {
+  	if (str.length == 0) return false
+  	let arr = []
+    let map = {
+        ')': '(',
+        '}': '{',
+        ']': '['
+    }
+    for (let i = 0; i < str.length; i++) {
+        if (str[i] == '(' || str[i] == '{' || str[i] == '[') {
+            arr.push(str[i])
+        } else {
+            //栈顶出栈的左括号 !== map取出右括号匹配的括号类型
+            if (map[str[i]] != arr.pop()) {
+                return false
+            }
+        }
+    }
+    // arr数组已全部匹配,出完栈
+    if (arr.length !== 0) {
+        return false
+    }
+    return true
+}
+
+//方案二:
+function isMatched(str) {
+  let stack = [];
+  let top = -1;
+
+  for (let i = 0; i < str.length; i++) {
+    let ch = str.charAt(i);
+
+    if (ch === '{' || ch === '[' || ch === '(') {
+      stack.push(ch);
+      top++;
+    } else if (ch === '}' && stack[top] === '{') {
+      stack.pop();
+      top--;
+    } else if (ch === ']' && stack[top] === '[') {
+      stack.pop();
+      top--;
+    } else if (ch === ')' && stack[top] === '(') {
+      stack.pop();
+      top--;
+    } else {
+      return false;
+    }
+  }
+
+  return stack.length === 0;
+}

解析:

  • 利用栈来实现括号匹配,用 top 标识栈顶元素的下标,初始值为 -1
  • 遍历字符串中的每个字符 ch
  • 如果是左括号 {[(,则入栈。
  • 如果是右括号 }]),则判断栈顶元素是否匹配,如果匹配则出栈,否则不匹配。
  • 如果字符不是括号,则返回 false
  • 最后,如果栈为空说明所有括号都匹配,返回 true,否则不匹配返回 false

简单递归

计算阶乘

js
function factorial(n) {
+  if (n === 0) {
+    return 1;
+  }
+  return n * factorial(n - 1);
+}
function factorial(n) {
+  if (n === 0) {
+    return 1;
+  }
+  return n * factorial(n - 1);
+}
  1. 计算斐波那契数列(Fibonacci)
js
function fibonacci(n) {
+  if (n <= 1) {
+    return n;
+  }
+  return fibonacci(n - 1) + fibonacci(n - 2);
+}
function fibonacci(n) {
+  if (n <= 1) {
+    return n;
+  }
+  return fibonacci(n - 1) + fibonacci(n - 2);
+}

扁平化数组

js
//ES6的flat方法实现:
+function flatten(array) {
+  return array.flat(Infinity)
+}
+//仅限二维数组
+function flat(arr){
+  return Array.prototype.concat.apply([],arr)
+}
+let array1 = [2,3,4,[4,6,5,8]]
+flat(array1)	[2, 3, 4, 4, 6, 5, 8]
+ 
+//多维数组
+function flatplus(arr){
+  while(arr.some(item => item instanceof Array)){
+    arr = Array.prototype.concat.apply([],arr)
+  }
+  return arr
+}
+let arr = [2,3,4,[5,[6,[7]]]]
+flatplus(arr)	//[2, 3, 4, 5, 6, 7]
+
+//可控制扁平化深度:Array.prototype.concat.apply
+function flatplus(arr,depth){
+  let deep = 0	
+  let flag = arr.some(item => item instanceof Array) && deep < depth
+  while(flag){
+    arr = Array.prototype.concat.apply([],arr)
+    ++deep
+  }
+  return arr
+}
+//递归+concat
+function flatten(arr) {
+  var result = [];
+ for (var i = 0; i < arr.length; i++) {
+    if (Array.isArray(arr[i])) {
+      result = result.concat(flatten(arr[i]));
+    } else {
+      result.push(arr[i]);
+    }
+  }
+  return result;
+}
//ES6的flat方法实现:
+function flatten(array) {
+  return array.flat(Infinity)
+}
+//仅限二维数组
+function flat(arr){
+  return Array.prototype.concat.apply([],arr)
+}
+let array1 = [2,3,4,[4,6,5,8]]
+flat(array1)	[2, 3, 4, 4, 6, 5, 8]
+ 
+//多维数组
+function flatplus(arr){
+  while(arr.some(item => item instanceof Array)){
+    arr = Array.prototype.concat.apply([],arr)
+  }
+  return arr
+}
+let arr = [2,3,4,[5,[6,[7]]]]
+flatplus(arr)	//[2, 3, 4, 5, 6, 7]
+
+//可控制扁平化深度:Array.prototype.concat.apply
+function flatplus(arr,depth){
+  let deep = 0	
+  let flag = arr.some(item => item instanceof Array) && deep < depth
+  while(flag){
+    arr = Array.prototype.concat.apply([],arr)
+    ++deep
+  }
+  return arr
+}
+//递归+concat
+function flatten(arr) {
+  var result = [];
+ for (var i = 0; i < arr.length; i++) {
+    if (Array.isArray(arr[i])) {
+      result = result.concat(flatten(arr[i]));
+    } else {
+      result.push(arr[i]);
+    }
+  }
+  return result;
+}

反转字符串

js
//解法一:使用数组的reverse()方法
+function reverseString(str) {
+  return str.split('').reverse().join('');
+}
+
+//解法二:使用for循环遍历字符串
+function reverseString(str) {
+  let result = '';
+  for (let i = str.length - 1; i >= 0; i--) {
+    result += str[i];
+  }
+  return result;
+}
+
+//解法三:使用递归函数
+function reverseString(str) {
+  if (str === "")	return "";
+  return reverseString(str.slice(1)) + str[0];
+}
//解法一:使用数组的reverse()方法
+function reverseString(str) {
+  return str.split('').reverse().join('');
+}
+
+//解法二:使用for循环遍历字符串
+function reverseString(str) {
+  let result = '';
+  for (let i = str.length - 1; i >= 0; i--) {
+    result += str[i];
+  }
+  return result;
+}
+
+//解法三:使用递归函数
+function reverseString(str) {
+  if (str === "")	return "";
+  return reverseString(str.slice(1)) + str[0];
+}

求最大公约数

js
function gcd(a, b) {
+  if (b === 0) return a;
+  return gcd(b, a % b);
+}
function gcd(a, b) {
+  if (b === 0) return a;
+  return gcd(b, a % b);
+}

斐波那契数列

js
//递归实现
+function fibonacci(n){
+  if(n<=1) return n;
+  return fibonacci(n-1) + fibonacci(n-2);
+}
+
+//动态规划实现
+function fibonacci(n){
+  let f = [0,1];
+  for(let i=2;i<=n;i++){
+    f[i] = f[i-1] + f[i-2];
+  }
+  return f[n];
+}
+
+//测试
+for(let i=0;i<=10;i++){
+  console.log(\`fibonacci(\${i}): \${fibonacci(i)}\`);
+  //输出:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
+}
//递归实现
+function fibonacci(n){
+  if(n<=1) return n;
+  return fibonacci(n-1) + fibonacci(n-2);
+}
+
+//动态规划实现
+function fibonacci(n){
+  let f = [0,1];
+  for(let i=2;i<=n;i++){
+    f[i] = f[i-1] + f[i-2];
+  }
+  return f[n];
+}
+
+//测试
+for(let i=0;i<=10;i++){
+  console.log(\`fibonacci(\${i}): \${fibonacci(i)}\`);
+  //输出:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
+}

排序算法

冒泡排序

js
function bubbleSort(arr) {
+  let len = arr.length;
+  for (let i = 0; i < len - 1; i++) {
+      for (let j = 0; j < len - 1 - i; j++) {
+          if (arr[j] > arr[j+1]) {
+            let temp = arr[j+1];
+            arr[j+1] = arr[j];
+            arr[j] = temp;
+            /*
+            不使用额外变量交换
+            方法一:
+            [arr[j+1],arr[j]] = [arr[j],arr[j+1]]
+
+            方法二:
+            a = a + b;
+            b = a - b;
+            a = a - b;
+
+            方法三:
+            a = a ^ b;
+            b = a ^ b;
+            a = a ^ b;
+            */
+          }
+      }
+  }
+  return arr;
+}
function bubbleSort(arr) {
+  let len = arr.length;
+  for (let i = 0; i < len - 1; i++) {
+      for (let j = 0; j < len - 1 - i; j++) {
+          if (arr[j] > arr[j+1]) {
+            let temp = arr[j+1];
+            arr[j+1] = arr[j];
+            arr[j] = temp;
+            /*
+            不使用额外变量交换
+            方法一:
+            [arr[j+1],arr[j]] = [arr[j],arr[j+1]]
+
+            方法二:
+            a = a + b;
+            b = a - b;
+            a = a - b;
+
+            方法三:
+            a = a ^ b;
+            b = a ^ b;
+            a = a ^ b;
+            */
+          }
+      }
+  }
+  return arr;
+}

选择排序

排序动画图解

随机生成测试数组

js
var testArr = []
+for (var i = 0; i < 10000; i++) {
+     testArr.push(Math.floor(Math.random() * 100000))
+}
var testArr = []
+for (var i = 0; i < 10000; i++) {
+     testArr.push(Math.floor(Math.random() * 100000))
+}
js
arr = [3,7,6,9,4,5,2,8]
+const selectSort = (arr) => {
+if (!Array.isArray(arr)) {
+    throw new Error(arr + "is not Array")
+}
+for (let i = 0; i < arr.length; i++) {
+    let minIndex = i;
+    //找到arr[i]后的最小值得索引
+    for (let j = i + 1; j < arr.length; j++) {
+        if (arr[j] < arr[minIndex]) {
+            minIndex = j
+        }
+    }
+    //交换
+    let tem = arr[i]
+    arr[i] = arr[minIndex]
+    arr[minIndex] = tem
+}
+return arr
+}
arr = [3,7,6,9,4,5,2,8]
+const selectSort = (arr) => {
+if (!Array.isArray(arr)) {
+    throw new Error(arr + "is not Array")
+}
+for (let i = 0; i < arr.length; i++) {
+    let minIndex = i;
+    //找到arr[i]后的最小值得索引
+    for (let j = i + 1; j < arr.length; j++) {
+        if (arr[j] < arr[minIndex]) {
+            minIndex = j
+        }
+    }
+    //交换
+    let tem = arr[i]
+    arr[i] = arr[minIndex]
+    arr[minIndex] = tem
+}
+return arr
+}

快速排序

js
function quickSort(arr) {
+    if (arr.length <= 1) return arr;
+ 
+    const pivotIndex = Math.floor(arr.length / 2);
+	//选中心轴索引,并选取中心轴的值
+    const pivot = arr.splice(pivotIndex, 1)[0];  
+    const left = [];  
+    const right = []; 
+    for (let i = 0; i < arr.length; i++) {    
+        //与中心轴比较,小的放在左数组,大的放在右数组 
+     	arr[i] <= pivot ? left.push(arr[i]) : right.push(arr[i])
+    }  
+    return quickSort(left).concat([pivot], quickSort(right));
+};
function quickSort(arr) {
+    if (arr.length <= 1) return arr;
+ 
+    const pivotIndex = Math.floor(arr.length / 2);
+	//选中心轴索引,并选取中心轴的值
+    const pivot = arr.splice(pivotIndex, 1)[0];  
+    const left = [];  
+    const right = []; 
+    for (let i = 0; i < arr.length; i++) {    
+        //与中心轴比较,小的放在左数组,大的放在右数组 
+     	arr[i] <= pivot ? left.push(arr[i]) : right.push(arr[i])
+    }  
+    return quickSort(left).concat([pivot], quickSort(right));
+};

插入排序

以第一个数为有序数组,让后面每一个数比较找位置并插入有序数组里。

若后面待插入的数大于有序数组的最后一个数,就放在原位;

若第小于有序数组的最后一个数,则进入while循环,在有序数组中找位置:

arr[preIndex]后移索引变为preIndex+1current插入到arr[preIndex]前一位,也就是arr[preindex-1+1]

js
function insertSort(arr) {
+    let len = arr.length;
+    let preIndex, current;
+    for (let i = 1; i < len; i++) {
+        preIndex = i - 1;
+        current = arr[i];
+      //  while (preIndex >= 0 && current < arr[preIndex]) {//从大到小
+        while (preIndex >= 0 && current < arr[preIndex]) {//从小到大
+            arr[preIndex + 1] = arr[preIndex];//后移
+            preIndex--;
+        }//退出while循环时,说明插入位置找到
+        arr[preIndex + 1] = current;
+    }
+    return arr;
+}
function insertSort(arr) {
+    let len = arr.length;
+    let preIndex, current;
+    for (let i = 1; i < len; i++) {
+        preIndex = i - 1;
+        current = arr[i];
+      //  while (preIndex >= 0 && current < arr[preIndex]) {//从大到小
+        while (preIndex >= 0 && current < arr[preIndex]) {//从小到大
+            arr[preIndex + 1] = arr[preIndex];//后移
+            preIndex--;
+        }//退出while循环时,说明插入位置找到
+        arr[preIndex + 1] = current;
+    }
+    return arr;
+}

希尔排序

js
function shellSort(array) {
+    let gap = Math.floor(array.length / 2);
+
+    while (1 <= gap) {
+        // 把距离为 gap 的元素编为一个组,扫描所有组
+        for (let i = gap; i < array.length; i++) {
+            let j = 0;
+            let temp = array[i];
+
+            // 对距离为 gap 的元素组进行排序
+            for (j = i - gap; j >= 0 && temp < array[j]; j -= gap) {
+                array[j + gap] = array[j];
+            }
+            array[j + gap] = temp;
+        }
+        gap = Math.floor(gap / 2); // 减小增量
+    }
+    return array;
+}
function shellSort(array) {
+    let gap = Math.floor(array.length / 2);
+
+    while (1 <= gap) {
+        // 把距离为 gap 的元素编为一个组,扫描所有组
+        for (let i = gap; i < array.length; i++) {
+            let j = 0;
+            let temp = array[i];
+
+            // 对距离为 gap 的元素组进行排序
+            for (j = i - gap; j >= 0 && temp < array[j]; j -= gap) {
+                array[j + gap] = array[j];
+            }
+            array[j + gap] = temp;
+        }
+        gap = Math.floor(gap / 2); // 减小增量
+    }
+    return array;
+}

求两个有序数组的中位数

js
//出这两个有序数组的中位数,时间复杂度为 O(m+n)
+function findMedianSortedArrays(nums1, nums2) {
+    const mergeArr = merge(nums1, nums2); // 合并两个有序数组
+    const len = mergeArr.length;
+    // 判断合并后的数组长度,分奇偶情况求中位数
+    if(len % 2 === 0) {
+        return (mergeArr[len/2-1] + mergeArr[len/2])/2;
+    } else {
+        return mergeArr[Math.floor(len/2)];
+    }
+}
+
+// 归并排序合并两个有序数组
+function merge(nums1, nums2) {
+    const result = [];
+    let i = 0, j = 0;
+    while(i < nums1.length && j < nums2.length) {
+        if(nums1[i] < nums2[j]) {
+            result.push(nums1[i]);
+            i++;
+        } else {
+            result.push(nums2[j]);
+            j++;
+        }
+    }
+    while(i < nums1.length) {
+        result.push(nums1[i]);
+        i++;
+    }
+    while(j < nums2.length) {
+        result.push(nums2[j]);
+        j++;
+    }
+    return result;
+}
//出这两个有序数组的中位数,时间复杂度为 O(m+n)
+function findMedianSortedArrays(nums1, nums2) {
+    const mergeArr = merge(nums1, nums2); // 合并两个有序数组
+    const len = mergeArr.length;
+    // 判断合并后的数组长度,分奇偶情况求中位数
+    if(len % 2 === 0) {
+        return (mergeArr[len/2-1] + mergeArr[len/2])/2;
+    } else {
+        return mergeArr[Math.floor(len/2)];
+    }
+}
+
+// 归并排序合并两个有序数组
+function merge(nums1, nums2) {
+    const result = [];
+    let i = 0, j = 0;
+    while(i < nums1.length && j < nums2.length) {
+        if(nums1[i] < nums2[j]) {
+            result.push(nums1[i]);
+            i++;
+        } else {
+            result.push(nums2[j]);
+            j++;
+        }
+    }
+    while(i < nums1.length) {
+        result.push(nums1[i]);
+        i++;
+    }
+    while(j < nums2.length) {
+        result.push(nums2[j]);
+        j++;
+    }
+    return result;
+}
js
function findMedianSortedArrays(nums1, nums2) {
+  const merge = (arr1, arr2) => {
+    const merged = [];
+    let i = 0, j = 0;
+
+    while (i < arr1.length && j < arr2.length) {
+      if (arr1[i] < arr2[j]) merged.push(arr1[i++]);
+      else merged.push(arr2[j++]);
+    }
+
+    return [...merged, ...arr1.slice(i), ...arr2.slice(j)];
+  }
+
+  const merged = merge(nums1, nums2);
+  const mid = Math.floor(merged.length / 2);
+
+  return merged.length % 2 === 0 ? (merged[mid - 1] + merged[mid]) / 2 : merged[mid];
+}
function findMedianSortedArrays(nums1, nums2) {
+  const merge = (arr1, arr2) => {
+    const merged = [];
+    let i = 0, j = 0;
+
+    while (i < arr1.length && j < arr2.length) {
+      if (arr1[i] < arr2[j]) merged.push(arr1[i++]);
+      else merged.push(arr2[j++]);
+    }
+
+    return [...merged, ...arr1.slice(i), ...arr2.slice(j)];
+  }
+
+  const merged = merge(nums1, nums2);
+  const mid = Math.floor(merged.length / 2);
+
+  return merged.length % 2 === 0 ? (merged[mid - 1] + merged[mid]) / 2 : merged[mid];
+}

实现EventEmitter

js
//可以添加事件侦听器,触发事件,并处理异步事件
+class EventEmitter {
+  constructor() {
+    this.registry = {};
+  }
+
+  on(eventName, listener) {
+    if (!this.registry[eventName]) {
+      this.registry[eventName] = [];
+    }
+    this.registry[eventName].push(listener);
+  }
+
+  emit(eventName, ...args) {
+    if (this.registry[eventName]) {
+      this.registry[eventName].forEach((listener) => {
+        setTimeout(() => {
+          listener(...args);
+        }, 0);
+      });
+    }
+  }
+}
//可以添加事件侦听器,触发事件,并处理异步事件
+class EventEmitter {
+  constructor() {
+    this.registry = {};
+  }
+
+  on(eventName, listener) {
+    if (!this.registry[eventName]) {
+      this.registry[eventName] = [];
+    }
+    this.registry[eventName].push(listener);
+  }
+
+  emit(eventName, ...args) {
+    if (this.registry[eventName]) {
+      this.registry[eventName].forEach((listener) => {
+        setTimeout(() => {
+          listener(...args);
+        }, 0);
+      });
+    }
+  }
+}
测试
js
const eventEmitter = new EventEmitter();
+
+eventEmitter.on('eventA', () => { console.log('eventA triggered'); });
+eventEmitter.on('eventB', () => { console.log('eventB triggered'); });
+
+eventEmitter.emit('eventA');
+eventEmitter.emit('eventB');
const eventEmitter = new EventEmitter();
+
+eventEmitter.on('eventA', () => { console.log('eventA triggered'); });
+eventEmitter.on('eventB', () => { console.log('eventB triggered'); });
+
+eventEmitter.emit('eventA');
+eventEmitter.emit('eventB');

生成随机十六进制颜色

方案一:

js
function randomHexColor() {
+  var red = Math.floor(Math.random() * 256).toString(16);
+  var green = Math.floor(Math.random() * 256).toString(16);
+  var blue = Math.floor(Math.random() * 256).toString(16);
+  return "#" + red + green + blue;
+}
function randomHexColor() {
+  var red = Math.floor(Math.random() * 256).toString(16);
+  var green = Math.floor(Math.random() * 256).toString(16);
+  var blue = Math.floor(Math.random() * 256).toString(16);
+  return "#" + red + green + blue;
+}

方案二:

js
function randomHexColor() {
+  var color = Math.floor(Math.random() * 16777215).toString(16);
+  return \`#\${color}\`;
+}
function randomHexColor() {
+  var color = Math.floor(Math.random() * 16777215).toString(16);
+  return \`#\${color}\`;
+}

方案三:

js
function randomHexColor() {
+  var hexColor = Array.from({length: 3}, () => Math.floor(Math.random() * 256).toString(16));
+  return "#" + hexColor.join("");
+}
function randomHexColor() {
+  var hexColor = Array.from({length: 3}, () => Math.floor(Math.random() * 256).toString(16));
+  return "#" + hexColor.join("");
+}

方案四:

js
function randomHexColor() {
+  let letters = "0123456789ABCDEF";
+  let color = "#";
+  for (let i = 0; i < 6; i++) {
+     color += letters[Math.floor(Math.random() * 16)];
+  }
+  return color;
+}
function randomHexColor() {
+  let letters = "0123456789ABCDEF";
+  let color = "#";
+  for (let i = 0; i < 6; i++) {
+     color += letters[Math.floor(Math.random() * 16)];
+  }
+  return color;
+}

方案五:

js
function randomHexColor() {
+  let color = Math.floor(Math.random() * 0xFFFFFF).toString(16);
+  return "#" + ("000000" + color).slice(-6);
+}
function randomHexColor() {
+  let color = Math.floor(Math.random() * 0xFFFFFF).toString(16);
+  return "#" + ("000000" + color).slice(-6);
+}

方案六:

js
let color = '#' + parseInt(Math.random() * 0x1000000).toString(16).padStart(6, '0')
let color = '#' + parseInt(Math.random() * 0x1000000).toString(16).padStart(6, '0')

方案七:

js
function randomColor() {
+    const r = (Math.floor(Math.random() * 255)).toString(16);
+    const g = (Math.floor(Math.random() * 255)).toString(16);
+    const b = (Math.floor(Math.random() * 255)).toString(16);
+    const a = (Math.random()).toString(16).slice(2, 4);
+    return \`#\` + r + g + b + a;
+  }
function randomColor() {
+    const r = (Math.floor(Math.random() * 255)).toString(16);
+    const g = (Math.floor(Math.random() * 255)).toString(16);
+    const b = (Math.floor(Math.random() * 255)).toString(16);
+    const a = (Math.random()).toString(16).slice(2, 4);
+    return \`#\` + r + g + b + a;
+  }

返回给定起止字符串月份中间所有月份

js
function getMonths(start, end) {
+  const startDate = new Date(start);
+  const endDate = new Date(end);
+  const months = [];
+
+  while (startDate <= endDate) {
+    const year = startDate.getFullYear();
+    const month = startDate.getMonth() + 1;
+    const monthStr = \`\${year}-\${month.toString().padStart(2, '0')}\`;
+
+  	months.push(monthStr)
+    startDate.setMonth(month);
+  }
+  return months
+}
function getMonths(start, end) {
+  const startDate = new Date(start);
+  const endDate = new Date(end);
+  const months = [];
+
+  while (startDate <= endDate) {
+    const year = startDate.getFullYear();
+    const month = startDate.getMonth() + 1;
+    const monthStr = \`\${year}-\${month.toString().padStart(2, '0')}\`;
+
+  	months.push(monthStr)
+    startDate.setMonth(month);
+  }
+  return months
+}

实现Promise的all方法

js
function promiseAll(promiseArr) {
+  return new Promise((resolve, reject) => {
+     if (!Array.isArray(promiseArr)) {
+      return reject(new TypeError('arguments should be an array'));
+    }
+    const resArr = [];
+    // let count = 0;
+    // for (let i = 0; i < promiseArr.length; i++) {
+    //   promiseArr[i]
+    //     .then((res) => {
+    //       count++;
+    //       resArr[i] = res;
+    //       if (count === promiseArr.length) {
+    //         resolve(resArr);
+    //       }
+    //     })
+    //     .catch((err) => {
+    //       reject(err);
+    //     });
+    // }
+    promiseArr.forEach((p,i) =>{
+      if(p instanceof Promise){
+          p.then(res => {
+          resArr[i] = res;
+          if(resArr.length == i +1) resolve(resArr)
+        }).catch(err => reject(err))
+      }else{
+        resArr[resArr.length] = p;
+      }
+    })
+     
+  });
+}
+
+// 使用示例
+let p1 = Promise.resolve(1);
+let p2 = new Promise((resolve, reject) => {
+    setTimeout(() => {
+        resolve(2)
+    }, 2000);
+});
+let p3 = Promise.resolve("error");
+
+let p = promiseAll([p1, p2, p3])
+  .then((res) => {
+    resolve(res); // [1, 2, "error"]
+  })
+  .catch((err) => {
+    reject(err); // error
+  });
+  p.then(res => console.log(res)).catch(err => console.log(err))
function promiseAll(promiseArr) {
+  return new Promise((resolve, reject) => {
+     if (!Array.isArray(promiseArr)) {
+      return reject(new TypeError('arguments should be an array'));
+    }
+    const resArr = [];
+    // let count = 0;
+    // for (let i = 0; i < promiseArr.length; i++) {
+    //   promiseArr[i]
+    //     .then((res) => {
+    //       count++;
+    //       resArr[i] = res;
+    //       if (count === promiseArr.length) {
+    //         resolve(resArr);
+    //       }
+    //     })
+    //     .catch((err) => {
+    //       reject(err);
+    //     });
+    // }
+    promiseArr.forEach((p,i) =>{
+      if(p instanceof Promise){
+          p.then(res => {
+          resArr[i] = res;
+          if(resArr.length == i +1) resolve(resArr)
+        }).catch(err => reject(err))
+      }else{
+        resArr[resArr.length] = p;
+      }
+    })
+     
+  });
+}
+
+// 使用示例
+let p1 = Promise.resolve(1);
+let p2 = new Promise((resolve, reject) => {
+    setTimeout(() => {
+        resolve(2)
+    }, 2000);
+});
+let p3 = Promise.resolve("error");
+
+let p = promiseAll([p1, p2, p3])
+  .then((res) => {
+    resolve(res); // [1, 2, "error"]
+  })
+  .catch((err) => {
+    reject(err); // error
+  });
+  p.then(res => console.log(res)).catch(err => console.log(err))

LRU缓存算法

js
//LRU缓存算法: 缓存固定大小,当缓存超出容量时,删除最久未被使用的元素
+class LRUCache {
+  constructor(capacity) {
+    this.capacity = capacity; // 缓存最大容量
+    this.cache = new Map(); // 使用Map来存储key-value
+  }
+  //获取缓存中对应key的值,如果不存在则返回-1
+  get(key) {
+    const cache = this.cache;
+    if (!cache.has(key)) {
+      return -1;
+    }
+    const value = cache.get(key);
+    // 将访问的元素删除并重新添加到最前面
+    cache.delete(key);
+    cache.set(key, value);
+    return value;
+  }
+
+  //添加一个元素到缓存中,并在超出容量时删除最久未被使用的元素
+  put(key, value) {
+    const cache = this.cache;
+    // 如果key已经存在,则先删除这个节点
+    if (cache.has(key)) {
+      cache.delete(key);
+    } else if (cache.size >= this.capacity) {
+      // 如果缓存超出容量,则删除最久未被使用的元素,即链表尾部元素
+      const keys = cache.keys();
+      const oldestKey = keys.next().value; // 链表头部是最久未使用的元素
+      cache.delete(oldestKey);
+    }
+    // 将新节点添加到链表头部
+    cache.set(key, value);
+  }
+}
//LRU缓存算法: 缓存固定大小,当缓存超出容量时,删除最久未被使用的元素
+class LRUCache {
+  constructor(capacity) {
+    this.capacity = capacity; // 缓存最大容量
+    this.cache = new Map(); // 使用Map来存储key-value
+  }
+  //获取缓存中对应key的值,如果不存在则返回-1
+  get(key) {
+    const cache = this.cache;
+    if (!cache.has(key)) {
+      return -1;
+    }
+    const value = cache.get(key);
+    // 将访问的元素删除并重新添加到最前面
+    cache.delete(key);
+    cache.set(key, value);
+    return value;
+  }
+
+  //添加一个元素到缓存中,并在超出容量时删除最久未被使用的元素
+  put(key, value) {
+    const cache = this.cache;
+    // 如果key已经存在,则先删除这个节点
+    if (cache.has(key)) {
+      cache.delete(key);
+    } else if (cache.size >= this.capacity) {
+      // 如果缓存超出容量,则删除最久未被使用的元素,即链表尾部元素
+      const keys = cache.keys();
+      const oldestKey = keys.next().value; // 链表头部是最久未使用的元素
+      cache.delete(oldestKey);
+    }
+    // 将新节点添加到链表头部
+    cache.set(key, value);
+  }
+}

使用示例:

js
const cache = new LRUCache(2);
+
+console.log(cache.put(1, 1)); // 缓存是 {1=1}
+console.log(cache.put(2, 2)); // 缓存是 {1=1, 2=2}
+console.log(cache.get(1)); // 返回 1
+console.log(cache.put(3, 3)); // 删除 key 2,缓存是 {1=1, 3=3}
+console.log(cache.get(2)); // 返回 -1
+console.log(cache.put(4, 4)); // 删除 key 1,缓存是 {3=3, 4=4}
+console.log(cache.get(1)); // 返回 -1
+console.log(cache.get(3)); // 返回 3
+console.log(cache.get(4)); // 返回 4
const cache = new LRUCache(2);
+
+console.log(cache.put(1, 1)); // 缓存是 {1=1}
+console.log(cache.put(2, 2)); // 缓存是 {1=1, 2=2}
+console.log(cache.get(1)); // 返回 1
+console.log(cache.put(3, 3)); // 删除 key 2,缓存是 {1=1, 3=3}
+console.log(cache.get(2)); // 返回 -1
+console.log(cache.put(4, 4)); // 删除 key 1,缓存是 {3=3, 4=4}
+console.log(cache.get(1)); // 返回 -1
+console.log(cache.get(3)); // 返回 3
+console.log(cache.get(4)); // 返回 4

不使用乘法符号乘法函数

js
//递归
+function multiply(x, y) {
+  if (y === 0) {
+    return 0;
+  }
+  if (y > 0) {
+    return x + multiply(x, y - 1);
+  }
+  if (y < 0) {
+    return -multiply(x, -y);
+  }
+}
+//for循环
+function multiply(a, b) {
+  let result = 0;
+  for(let i = 0; i < Math.abs(b); i++) {
+    result += Math.abs(a);
+  }
+  if(a < 0 && b > 0 || a > 0 && b < 0) {
+    result = -result;
+  }
+  return result;
+}
+
+console.log(multiply(5, 3)); // 15
+console.log(multiply(-5, 3)); // -15
+console.log(multiply(5, -3)); // -15
+console.log(multiply(-5, -3)); // 15
//递归
+function multiply(x, y) {
+  if (y === 0) {
+    return 0;
+  }
+  if (y > 0) {
+    return x + multiply(x, y - 1);
+  }
+  if (y < 0) {
+    return -multiply(x, -y);
+  }
+}
+//for循环
+function multiply(a, b) {
+  let result = 0;
+  for(let i = 0; i < Math.abs(b); i++) {
+    result += Math.abs(a);
+  }
+  if(a < 0 && b > 0 || a > 0 && b < 0) {
+    result = -result;
+  }
+  return result;
+}
+
+console.log(multiply(5, 3)); // 15
+console.log(multiply(-5, 3)); // -15
+console.log(multiply(5, -3)); // -15
+console.log(multiply(-5, -3)); // 15

链表反转

js
function reverseLinkedList(head) {
+  let prev = null;
+  let current = head;
+  while (current !== null) {
+    let next = current.next;
+    current.next = prev;
+    prev = current;
+    current = next;
+  }
+  return prev;
+}
+
+//测试
+class Node {
+  constructor(value, next = null) {
+    this.value = value;
+    this.next = next;
+  }
+}
+
+let n1 = new Node(1);
+let n2 = new Node(2);
+let n3 = new Node(3);
+let n4 = new Node(4);
+let n5 = new Node(5);
+
+n1.next = n2;
+n2.next = n3;
+n3.next = n4;
+n4.next = n5;
+
+let head = n1;
+console.log("Original LinkedList: ");
+printLinkedList(head);
+
+head = reverseLinkedList(head);
+console.log("\\nReversed LinkedList: ");
+printLinkedList(head);
+
+function printLinkedList(head) {
+  let current = head;
+  while (current !== null) {
+    process.stdout.write(current.value + " ");
+    current = current.next;
+  }
+}
function reverseLinkedList(head) {
+  let prev = null;
+  let current = head;
+  while (current !== null) {
+    let next = current.next;
+    current.next = prev;
+    prev = current;
+    current = next;
+  }
+  return prev;
+}
+
+//测试
+class Node {
+  constructor(value, next = null) {
+    this.value = value;
+    this.next = next;
+  }
+}
+
+let n1 = new Node(1);
+let n2 = new Node(2);
+let n3 = new Node(3);
+let n4 = new Node(4);
+let n5 = new Node(5);
+
+n1.next = n2;
+n2.next = n3;
+n3.next = n4;
+n4.next = n5;
+
+let head = n1;
+console.log("Original LinkedList: ");
+printLinkedList(head);
+
+head = reverseLinkedList(head);
+console.log("\\nReversed LinkedList: ");
+printLinkedList(head);
+
+function printLinkedList(head) {
+  let current = head;
+  while (current !== null) {
+    process.stdout.write(current.value + " ");
+    current = current.next;
+  }
+}

二叉树的遍历

二叉树三种遍历方式

  • 前序遍历:先访问节点,然后再访问左子树和右子树。
  • 中序遍历:先访问左子树,然后访问节点,最后访问右子树。
  • 后序遍历:先访问左子树,然后访问右子树,最后访问节点。
javascript
// 定义二叉树节点类
+class TreeNode {
+  constructor(val) {
+    this.val = val;
+    this.left = null;
+    this.right = null;
+  }
+}
+
+// 前序遍历
+function preOrderTraversal(root, res = []) {
+  if (!root) return res;
+  res.push(root.val);
+  preOrderTraversal(root.left, res);
+  preOrderTraversal(root.right, res);
+  return res;
+}
+
+// 中序遍历
+function inOrderTraversal(root, res = []) {
+  if (!root) return res;
+  inOrderTraversal(root.left, res);
+  res.push(root.val);
+  inOrderTraversal(root.right, res);
+  return res;
+}
+
+// 后序遍历
+function postOrderTraversal(root, res = []) {
+  if (!root) return res;
+  postOrderTraversal(root.left, res);
+  postOrderTraversal(root.right, res);
+  res.push(root.val);
+  return res;
+}
// 定义二叉树节点类
+class TreeNode {
+  constructor(val) {
+    this.val = val;
+    this.left = null;
+    this.right = null;
+  }
+}
+
+// 前序遍历
+function preOrderTraversal(root, res = []) {
+  if (!root) return res;
+  res.push(root.val);
+  preOrderTraversal(root.left, res);
+  preOrderTraversal(root.right, res);
+  return res;
+}
+
+// 中序遍历
+function inOrderTraversal(root, res = []) {
+  if (!root) return res;
+  inOrderTraversal(root.left, res);
+  res.push(root.val);
+  inOrderTraversal(root.right, res);
+  return res;
+}
+
+// 后序遍历
+function postOrderTraversal(root, res = []) {
+  if (!root) return res;
+  postOrderTraversal(root.left, res);
+  postOrderTraversal(root.right, res);
+  res.push(root.val);
+  return res;
+}
测试
js
/* ------------- 测试 -------------- */
+
+//     1
+//   /   \\
+//  2     3
+// / \\   / \\
+//4   5 6   7
+const root = new TreeNode(1);
+root.left = new TreeNode(2);
+root.left.left = new TreeNode(4);
+root.left.right = new TreeNode(5);
+root.right = new TreeNode(3);
+root.right.left = new TreeNode(6);
+root.right.right = new TreeNode(7);
+
+console.log(preOrderTraversal(root));   // [1, 2, 4, 5, 3, 6, 7]
+console.log(inOrderTraversal(root));    // [4, 2, 5, 1, 6, 3, 7]
+console.log(postOrderTraversal(root));  // [4, 5, 2, 6, 7, 3, 1]
/* ------------- 测试 -------------- */
+
+//     1
+//   /   \\
+//  2     3
+// / \\   / \\
+//4   5 6   7
+const root = new TreeNode(1);
+root.left = new TreeNode(2);
+root.left.left = new TreeNode(4);
+root.left.right = new TreeNode(5);
+root.right = new TreeNode(3);
+root.right.left = new TreeNode(6);
+root.right.right = new TreeNode(7);
+
+console.log(preOrderTraversal(root));   // [1, 2, 4, 5, 3, 6, 7]
+console.log(inOrderTraversal(root));    // [4, 2, 5, 1, 6, 3, 7]
+console.log(postOrderTraversal(root));  // [4, 5, 2, 6, 7, 3, 1]

二叉搜索树的插入和查找

js
递归实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+  } else {
+    this.insertNode(this.root, newNode);
+  }
+};
+
+BST.prototype.insertNode = function(node, newNode) {
+  if (newNode.value < node.value) {
+    if (node.left === null) {
+      node.left = newNode;
+    } else {
+      this.insertNode(node.left, newNode);
+    }
+  } else {
+    if (node.right === null) {
+      node.right = newNode;
+    } else {
+      this.insertNode(node.right, newNode);
+    }
+  }
+};
+
+BST.prototype.search = function(value) { 
+  return this.searchNode(this.root, value); 
+};
+
+BST.prototype.searchNode = function(node, value) { 
+  if (node === null) {
+    return false;
+  } else if (value < node.value) {
+    return this.searchNode(node.left, value);
+  } else if (value > node.value) {
+    return this.searchNode(node.right, value);
+  } else {
+    return true;
+  }
+};
+
+循环实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+    return;
+  }
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      if (current.left === null) {
+        current.left = newNode;
+        return;
+      }
+      current = current.left;
+    } else {
+      if (current.right === null) {
+        current.right = newNode;
+        return;
+      }
+      current = current.right;
+    }
+  }
+};
+
+BST.prototype.search = function(value) {
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      current = current.left;
+    } else if (value > current.value) {
+      current = current.right;
+    } else {
+      return true;
+    }
+  }
+  return false;
+};
递归实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+  } else {
+    this.insertNode(this.root, newNode);
+  }
+};
+
+BST.prototype.insertNode = function(node, newNode) {
+  if (newNode.value < node.value) {
+    if (node.left === null) {
+      node.left = newNode;
+    } else {
+      this.insertNode(node.left, newNode);
+    }
+  } else {
+    if (node.right === null) {
+      node.right = newNode;
+    } else {
+      this.insertNode(node.right, newNode);
+    }
+  }
+};
+
+BST.prototype.search = function(value) { 
+  return this.searchNode(this.root, value); 
+};
+
+BST.prototype.searchNode = function(node, value) { 
+  if (node === null) {
+    return false;
+  } else if (value < node.value) {
+    return this.searchNode(node.left, value);
+  } else if (value > node.value) {
+    return this.searchNode(node.right, value);
+  } else {
+    return true;
+  }
+};
+
+循环实现
+
+function Node(value) {
+  this.value = value;
+  this.left = null;
+  this.right = null;
+}
+
+function BST() {
+  this.root = null;
+}
+
+BST.prototype.insert = function(value) {
+  var newNode = new Node(value);
+  if (this.root === null) {
+    this.root = newNode;
+    return;
+  }
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      if (current.left === null) {
+        current.left = newNode;
+        return;
+      }
+      current = current.left;
+    } else {
+      if (current.right === null) {
+        current.right = newNode;
+        return;
+      }
+      current = current.right;
+    }
+  }
+};
+
+BST.prototype.search = function(value) {
+  var current = this.root;
+  while (current !== null) {
+    if (value < current.value) {
+      current = current.left;
+    } else if (value > current.value) {
+      current = current.right;
+    } else {
+      return true;
+    }
+  }
+  return false;
+};

字符串搜索算法

javascript
//KMP算法是一种高效的字符串搜索算法,在对文本串和模式串进行匹配时,通过利用前缀表来避免不必要的比较,从而实现快速匹配。
+function kmp(text, pattern) {
+  let n = text.length;
+  let m = pattern.length;
+
+  // 构建前缀表
+  let prefix = Array(m).fill(0);
+  let j = 0;
+  for (let i = 1; i < m; i++) {
+    while (j > 0 && pattern[j] !== pattern[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === pattern[i]) {
+      j++;
+    }
+    prefix[i] = j;
+  }
+
+  // 匹配文本串和模式串
+  j = 0;
+  for (let i = 0; i < n; i++) {
+    while (j > 0 && pattern[j] !== text[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === text[i]) {
+      j++;
+    }
+    if (j === m) {
+      return i - m + 1;
+    }
+  }
+
+  return -1;
+}
//KMP算法是一种高效的字符串搜索算法,在对文本串和模式串进行匹配时,通过利用前缀表来避免不必要的比较,从而实现快速匹配。
+function kmp(text, pattern) {
+  let n = text.length;
+  let m = pattern.length;
+
+  // 构建前缀表
+  let prefix = Array(m).fill(0);
+  let j = 0;
+  for (let i = 1; i < m; i++) {
+    while (j > 0 && pattern[j] !== pattern[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === pattern[i]) {
+      j++;
+    }
+    prefix[i] = j;
+  }
+
+  // 匹配文本串和模式串
+  j = 0;
+  for (let i = 0; i < n; i++) {
+    while (j > 0 && pattern[j] !== text[i]) {
+      j = prefix[j - 1];
+    }
+    if (pattern[j] === text[i]) {
+      j++;
+    }
+    if (j === m) {
+      return i - m + 1;
+    }
+  }
+
+  return -1;
+}

在这个函数中,我们首先计算出模式串的前缀表,然后逐个字符地扫描文本串和模式串,利用前缀表来确定匹配的位置。

接下来,我们可以使用这个函数来测试一下:

javascript
let text = "hello world";
+let pattern = "world";
+let index = kmp(text, pattern);
+console.log(index); // 输出5
let text = "hello world";
+let pattern = "world";
+let index = kmp(text, pattern);
+console.log(index); // 输出5

在这个例子中,我们将文本串设置为“hello world”,将模式串设置为“world”,然后调用kmp函数来查找匹配位置。由于模式串出现在文本串的位置是5,所以kmp函数返回的结果也是5。

这里还可以尝试一些其他的测试用例,例如:

javascript
let text = "abababaababacb";
+let pattern = "ababacb";
+let index = kmp(text, pattern);
+console.log(index); // 输出7
let text = "abababaababacb";
+let pattern = "ababacb";
+let index = kmp(text, pattern);
+console.log(index); // 输出7

这个例子中,我们将文本串设置为“abababaababacb”,将模式串设置为“ababacb”,然后调用kmp函数来查找匹配位置。由于模式串出现在文本串的位置是7,所以kmp函数返回的结果也是7。

总之,KMP算法是一种高效的字符串搜索算法,通过利用前缀表来避免不必要的比较,能够快速地查找匹配位置。

数字转中文

方法一:

js
function numberToChinese(num, upper = false) {
+  if (!/^(\\-|\\+)?\\d*(\\.\\d*)?$/.test(num)) {
+    return "不是一个合法的数字!";
+  }
+  let digitMap = {
+    plain:["", "", "", "", "", "", "", "", "", ""],
+    upper:["", "", "", "", "", "", "", "", "", ""]
+  }
+  let unitMap = {
+    plain: [
+      ["", "", "亿"],
+      ["", "", "", ""],
+    ],
+    upper: [
+      ["", "", ""],
+      ["", "", "", ""],
+    ],
+  };
+  let ustr = upper ? "upper" : "plain"
+  let head = num < 0 ? "" : "";
+  let unit = unitMap[ustr];
+  num = Math.abs(num);
+  let result = "";
+  for (let i = 0; i < unit[0].length && num > 0; i++) {
+    let currUnit = "";
+    for (let j = 0; j < unit[1].length && num > 0; j++) {
+      let index = num % 10;
+      let d =digitMap[ustr];
+      currUnit = d + unit[1][j] + currUnit;
+      num = Math.floor(num / 10);
+    }
+    result =
+      currUnit.replace(/(.)*$/, "").replace(/^$/, "") +
+      unit[0][i] +
+      result;
+  }
+  let reg = upper ? /億零{0,3}/ : /亿零{0,3}/;
+  let lastres =
+    head +
+    result
+      .replace(/(.)*零元/, "")
+      .replace(/(.)+/g, "")
+      .replace(reg, upper ? "" : "亿")
+      .replace(/^+/, "");
+  return lastres;
+}
function numberToChinese(num, upper = false) {
+  if (!/^(\\-|\\+)?\\d*(\\.\\d*)?$/.test(num)) {
+    return "不是一个合法的数字!";
+  }
+  let digitMap = {
+    plain:["", "", "", "", "", "", "", "", "", ""],
+    upper:["", "", "", "", "", "", "", "", "", ""]
+  }
+  let unitMap = {
+    plain: [
+      ["", "", "亿"],
+      ["", "", "", ""],
+    ],
+    upper: [
+      ["", "", ""],
+      ["", "", "", ""],
+    ],
+  };
+  let ustr = upper ? "upper" : "plain"
+  let head = num < 0 ? "" : "";
+  let unit = unitMap[ustr];
+  num = Math.abs(num);
+  let result = "";
+  for (let i = 0; i < unit[0].length && num > 0; i++) {
+    let currUnit = "";
+    for (let j = 0; j < unit[1].length && num > 0; j++) {
+      let index = num % 10;
+      let d =digitMap[ustr];
+      currUnit = d + unit[1][j] + currUnit;
+      num = Math.floor(num / 10);
+    }
+    result =
+      currUnit.replace(/(.)*$/, "").replace(/^$/, "") +
+      unit[0][i] +
+      result;
+  }
+  let reg = upper ? /億零{0,3}/ : /亿零{0,3}/;
+  let lastres =
+    head +
+    result
+      .replace(/(.)*零元/, "")
+      .replace(/(.)+/g, "")
+      .replace(reg, upper ? "" : "亿")
+      .replace(/^+/, "");
+  return lastres;
+}

方法二:

js
function numberToChinese(num) {
+  if (num === 0) return "";
+  //数字超过999999999999则报错
+  if (num.toString().length > 12) {
+    throw new Error("数字过大,无法转换");
+  }
+  let cstr = "";
+  let bunits = ["", "", "亿"];
+  //把数字转换成字符串,四位一组,从后往前分割
+  let numStr = num
+    .toString()
+    .split("")
+    .reverse()
+    .join("")
+    .match(/(\\d{1,4})/g)
+    .join(",")
+    .split("")
+    .reverse()
+    .join("")
+    .split(",");
+  let len = numStr.length;
+
+  function transform(str) {
+    let res = "";
+    let carr = ["", "", "", "", "", "", "", "", "", ""];
+    let units = ["", "", "", ""];
+    for (let i = 0; i < str.length; i++) {
+      let digit = +str[i];
+      let char = carr[digit];
+      let unit = units[str.length - i - 1];
+      if (digit === 0) {
+        //如果是0,且不是最后一位不是零,则加零,并且不加单位
+        if (res[res.length - 1] !== "") {
+          res += char;
+        }
+      } else {
+        res += char + unit;
+      }
+    }
+    if (res[res.length - 1] === "") {
+      res = res.slice(0, res.length - 1);
+    }
+    return res;
+  }
+  for (let i = 0; i < len; i++) {
+    let part = numStr[i];
+    let str = transform(part);
+    let unit = str ? bunits[len - i - 1] : "";
+    cstr += str + unit;
+  }
+  cstr.startsWith("一十") && (cstr = cstr.slice(1));
+  return cstr;
+}
+
+//大写中文
+function bigChinese(str){
+  let  map ={
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '亿':'',
+  }
+  let s = numberToChinese(str)
+  return s.split('').map( item => map[item]).join('')
+
+}
+let n = bigChinese(1000100001); //拾億零壹拾萬零壹
+console.log('[ n ]-66', n)
function numberToChinese(num) {
+  if (num === 0) return "";
+  //数字超过999999999999则报错
+  if (num.toString().length > 12) {
+    throw new Error("数字过大,无法转换");
+  }
+  let cstr = "";
+  let bunits = ["", "", "亿"];
+  //把数字转换成字符串,四位一组,从后往前分割
+  let numStr = num
+    .toString()
+    .split("")
+    .reverse()
+    .join("")
+    .match(/(\\d{1,4})/g)
+    .join(",")
+    .split("")
+    .reverse()
+    .join("")
+    .split(",");
+  let len = numStr.length;
+
+  function transform(str) {
+    let res = "";
+    let carr = ["", "", "", "", "", "", "", "", "", ""];
+    let units = ["", "", "", ""];
+    for (let i = 0; i < str.length; i++) {
+      let digit = +str[i];
+      let char = carr[digit];
+      let unit = units[str.length - i - 1];
+      if (digit === 0) {
+        //如果是0,且不是最后一位不是零,则加零,并且不加单位
+        if (res[res.length - 1] !== "") {
+          res += char;
+        }
+      } else {
+        res += char + unit;
+      }
+    }
+    if (res[res.length - 1] === "") {
+      res = res.slice(0, res.length - 1);
+    }
+    return res;
+  }
+  for (let i = 0; i < len; i++) {
+    let part = numStr[i];
+    let str = transform(part);
+    let unit = str ? bunits[len - i - 1] : "";
+    cstr += str + unit;
+  }
+  cstr.startsWith("一十") && (cstr = cstr.slice(1));
+  return cstr;
+}
+
+//大写中文
+function bigChinese(str){
+  let  map ={
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '':'',
+    '亿':'',
+  }
+  let s = numberToChinese(str)
+  return s.split('').map( item => map[item]).join('')
+
+}
+let n = bigChinese(1000100001); //拾億零壹拾萬零壹
+console.log('[ n ]-66', n)
`,92),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const i=s(p,[["render",t]]);export{C as __pageData,i as default}; diff --git "a/assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.lean.js" "b/assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.lean.js" new file mode 100644 index 00000000..3a742028 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\345\270\270\350\247\201\347\256\227\346\263\225.md.0cd56de3.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/常见算法.md","filePath":"FrontEnd/JavaScript/常见算法.md"}'),p={name:"FrontEnd/JavaScript/常见算法.md"},o=l("",92),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const i=s(p,[["render",t]]);export{C as __pageData,i as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.js" "b/assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.js" new file mode 100644 index 00000000..014e3895 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.js" @@ -0,0 +1,1149 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/手写Promise.md","filePath":"FrontEnd/JavaScript/手写Promise.md"}'),p={name:"FrontEnd/JavaScript/手写Promise.md"},o=l(`

一、声名Promise并绑定this

js
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        }
+        // 3.成功状态
+    resolve(value) {
+            this.status = Promise.FUFILLED
+            this.value = value
+        }
+        // 4.失败状态
+    reject(reason) {
+        this.status = Promise.REJECTED
+        this.reason = reason
+    }
+}
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        }
+        // 3.成功状态
+    resolve(value) {
+            this.status = Promise.FUFILLED
+            this.value = value
+        }
+        // 4.失败状态
+    reject(reason) {
+        this.status = Promise.REJECTED
+        this.reason = reason
+    }
+}

问题一:能多次修改状态

html
<!DOCTYPE html>
+
+<head>
+    <title>My-Promise</title>
+    <script src="./Promise.js"></script>
+</head>
+
+<body>
+    <script>
+        var p1 = new Promise((resolve, reject) => {
+            resolve('大功告成!')
+            reject('一败涂地!')
+        })
+        console.log(p1);
+    </script>
+</body>
+
+</html>
<!DOCTYPE html>
+
+<head>
+    <title>My-Promise</title>
+    <script src="./Promise.js"></script>
+</head>
+
+<body>
+    <script>
+        var p1 = new Promise((resolve, reject) => {
+            resolve('大功告成!')
+            reject('一败涂地!')
+        })
+        console.log(p1);
+    </script>
+</body>
+
+</html>

二、状态保护与执行者异步捕获

改变状态前先判断,让初始状态只能修改一次

js
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            try {
+                executor(this.resolve.bind(this), this.reject.bind(this))
+            } catch {
+
+            }
+
+        }
+        // 3.成功状态
+    resolve(value) {
+            //判断是不是初始态
+            if (this.status == Promise.PENDING) {
+                this.status = Promise.FUFILLED
+                this.value = value
+            }
+
+        }
+        // 4.失败状态
+    reject(reason) {
+        //判断是不是初始态
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED
+            this.reason = reason
+        }
+    }
+}
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+        // 2.构造函数
+    constructor(executor) {
+            //初始态
+            this.status = Promise.PENDING
+            this.value = null
+                // 绑定this
+            try {
+                executor(this.resolve.bind(this), this.reject.bind(this))
+            } catch {
+
+            }
+
+        }
+        // 3.成功状态
+    resolve(value) {
+            //判断是不是初始态
+            if (this.status == Promise.PENDING) {
+                this.status = Promise.FUFILLED
+                this.value = value
+            }
+
+        }
+        // 4.失败状态
+    reject(reason) {
+        //判断是不是初始态
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED
+            this.reason = reason
+        }
+    }
+}

三、then方法构建

js
 then(onFulfilled, onRejected) {
+        if (typeof onFulfilled !== 'function') {
+            onFulfilled = () => {}
+        }
+        if (typeof onRejected !== 'function') {
+            onRejected = () => {}
+        }
+        if (this.status == Promise.FUFILLED) {
+            onFulfilled(this.value)
+        }
+        if (this.status == Promise.REJECTED) {
+            onRejected(this.value)
+        }
+    }
 then(onFulfilled, onRejected) {
+        if (typeof onFulfilled !== 'function') {
+            onFulfilled = () => {}
+        }
+        if (typeof onRejected !== 'function') {
+            onRejected = () => {}
+        }
+        if (this.status == Promise.FUFILLED) {
+            onFulfilled(this.value)
+        }
+        if (this.status == Promise.REJECTED) {
+            onRejected(this.value)
+        }
+    }

四、实现then异步

js
if (this.status == Promise.FUFILLED) {
+    setTimeout(() => {
+        try {
+            onFulfilled(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            onRejected(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+        }
if (this.status == Promise.FUFILLED) {
+    setTimeout(() => {
+        try {
+            onFulfilled(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            onRejected(this.value)
+        } catch (error) {
+            onRejected(error)
+        }
+    });
+        }

五、解决同步代码需要等待执行问题

js
var p1 = new Promise((resolve, reject) => {
+        // resolve('大功告成!')S
+        setTimeout(() => {
+            reject('一败涂地!')
+            console.log('反败为胜!');
+        }, 100)
+
+    })
+    p1.then((value) => {
+        console.log(value);
+    }, (reason) => {
+        console.log(reason);
+    })
+    console.log('同步代码');
var p1 = new Promise((resolve, reject) => {
+        // resolve('大功告成!')S
+        setTimeout(() => {
+            reject('一败涂地!')
+            console.log('反败为胜!');
+        }, 100)
+
+    })
+    p1.then((value) => {
+        console.log(value);
+    }, (reason) => {
+        console.log(reason);
+    })
+    console.log('同步代码');

解决前输出: 同步代码 一败涂地! 反败为胜!

js
    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onRejected(value);
+                });
+            });
+        }
+    }
    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+            setTimeout(() => {
+                this.callbacks.map(callback => {
+                    callback.onRejected(value);
+                });
+            });
+        }
+    }

解决后输出: 同步代码 反败为胜! 一败涂地!

六、then的链式操作

注意点:

  1. then返回的时Promise,Promise需要改变
  2. 之前的Promise状态并不会影响之后的Promise状态
js
let p = new Promise((resolve, reject) => {
+        resolve("大功告成!");
+        // reject("一败涂地!");
+        console.log("状态绑定成功!");
+    })
+    p.then(
+            value => {
+                console.log(value);
+                return "马到功成!";
+            },
+            reason => {
+                console.log(reason);
+                return '优胜劣败!'
+            }
+        )
+        .then(
+            value => {
+                console.log(value);
+            },
+            reason => {
+                console.log(reason);
+            }
+        );
+    console.log("同步代码");
let p = new Promise((resolve, reject) => {
+        resolve("大功告成!");
+        // reject("一败涂地!");
+        console.log("状态绑定成功!");
+    })
+    p.then(
+            value => {
+                console.log(value);
+                return "马到功成!";
+            },
+            reason => {
+                console.log(reason);
+                return '优胜劣败!'
+            }
+        )
+        .then(
+            value => {
+                console.log(value);
+            },
+            reason => {
+                console.log(reason);
+            }
+        );
+    console.log("同步代码");
js
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        //then的穿透处理
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+         //then的穿透处理
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    try {
+                        let result = onFulfilled(value);
+                        resolve(result);
+                    } catch (error) {
+                        reject(error);
+                    }
+                },
+                onRejected: value => {
+                    try {
+                        let result = onRejected(value);
+                        resolve(result);
+                    } catch (error) { 
+                        reject(error);
+                    }
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                try {
+                    let result = onFulfilled(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                try {
+                    let result = onRejected(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+    });
+}
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        //then的穿透处理
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+         //then的穿透处理
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    try {
+                        let result = onFulfilled(value);
+                        resolve(result);
+                    } catch (error) {
+                        reject(error);
+                    }
+                },
+                onRejected: value => {
+                    try {
+                        let result = onRejected(value);
+                        resolve(result);
+                    } catch (error) { 
+                        reject(error);
+                    }
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                try {
+                    let result = onFulfilled(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                try {
+                    let result = onRejected(this.value);
+                    resolve(result);
+                } catch (error) { //解决异常
+                    reject(error);
+                }
+            });
+        }
+    });
+}

执行结果:

七、返回值的判断与处理

判断并分别处理返回值为Promise、普通值的情况

js
if (this.status == Promise.FULFILLED) {
+    setTimeout(() => {
+        try {
+            let result = onFulfilled(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            let result = onRejected(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}
if (this.status == Promise.FULFILLED) {
+    setTimeout(() => {
+        try {
+            let result = onFulfilled(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}
+if (this.status == Promise.REJECTED) {
+    setTimeout(() => {
+        try {
+            let result = onRejected(this.value);
+            // 判断并处理返回值 
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    });
+}

八、代码优化及复用

js
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    // try {
+                    //     let result = onFulfilled(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     reject(error);
+                    // }
+                    this.parse(onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    // try {
+                    //     let result = onRejected(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     //解决异常
+                    //     reject(error);
+                    // }
+                    this.parse(onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onFulfilled(this.value);
+                //     // resolve(result)
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onRejected(this.value);
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+}
+//抽取方法
+parse(result, resolve, reject) {
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    return new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    // try {
+                    //     let result = onFulfilled(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     reject(error);
+                    // }
+                    this.parse(onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    // try {
+                    //     let result = onRejected(value);
+                    //     resolve(result);
+                    // } catch (error) {
+                    //     //解决异常
+                    //     reject(error);
+                    // }
+                    this.parse(onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onFulfilled(this.value);
+                //     // resolve(result)
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                // try {
+                //     let result = onRejected(this.value);
+                //     if (result instanceof Promise) {
+                //         result.then(resolve, reject);
+                //     } else {
+                //         resolve(result);
+                //     }
+                // } catch (error) {
+                //     reject(error);
+                // }
+                this.parse(onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+}
+//抽取方法
+parse(result, resolve, reject) {
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}

九、返回类型约束

当前Promise不能返回自己

js
let p = promise.then(value => return p) //原生的会报错:TypeError
let p = promise.then(value => return p) //原生的会报错:TypeError
js
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    let promise = new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                this.parse(promise, onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                this.parse(promise, onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+    return promise;
+}
+parse(promise, result, resolve, reject) {
+    if (promise == result) {
+        throw new TypeError("Chaining cycle detected for promise");
+    }
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}
then(onFulfilled, onRejected) {
+    if (typeof onFulfilled != "function") {
+        onFulfilled = value => value;
+    }
+    if (typeof onRejected != "function") {
+        onRejected = value => value;
+    }
+    let promise = new Promise((resolve, reject) => {
+        if (this.status == Promise.PENDING) {
+            this.callbacks.push({
+                onFulfilled: value => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                },
+                onRejected: value => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                }
+            });
+        }
+        if (this.status == Promise.FULFILLED) {
+            setTimeout(() => {
+                this.parse(promise, onFulfilled(this.value), resolve, reject);
+            });
+        }
+        if (this.status == Promise.REJECTED) {
+            setTimeout(() => {
+                this.parse(promise, onRejected(this.value), resolve, reject);
+            });
+        }
+    });
+    return promise;
+}
+parse(promise, result, resolve, reject) {
+    if (promise == result) {
+        throw new TypeError("Chaining cycle detected for promise");
+    }
+    try {
+        if (result instanceof Promise) {
+            result.then(resolve, reject);
+        } else {
+            resolve(result);
+        }
+    } catch (error) {
+        reject(error);
+    }
+}

十、实现resolve和reject

js
 static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }
 static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }

十一、Promise.all()实现

js
static all(promises) {
+    let resolves = [];
+    return new Promise((resolve, reject) => {
+        promises.forEach((promise, index) => {
+            promise.then(
+                value => {
+                    resolves.push(value);
+                    //判断数组长度,来看是否全部成功
+                    if (resolves.length == promises.length) {
+                        resolve(resolves);
+                    }
+                },
+                reason => {
+                    reject(reason);
+                }
+            );
+        });
+    });
+}
static all(promises) {
+    let resolves = [];
+    return new Promise((resolve, reject) => {
+        promises.forEach((promise, index) => {
+            promise.then(
+                value => {
+                    resolves.push(value);
+                    //判断数组长度,来看是否全部成功
+                    if (resolves.length == promises.length) {
+                        resolve(resolves);
+                    }
+                },
+                reason => {
+                    reject(reason);
+                }
+            );
+        });
+    });
+}

测试

js
let p1 = new Promise((resolve, reject) => {
+        resolve("成功");
+    });
+let p2 = new Promise((resolve, reject) => {
+    reject("失败");
+});
+//所有成功才会执行成功的回调函数
+let promises = Promise.all([p1, p2]).then(
+    promises => {
+        console.log('resolve:', promises);
+    },
+    reason => {
+        console.log('reject:', reason);
+    }
+);
let p1 = new Promise((resolve, reject) => {
+        resolve("成功");
+    });
+let p2 = new Promise((resolve, reject) => {
+    reject("失败");
+});
+//所有成功才会执行成功的回调函数
+let promises = Promise.all([p1, p2]).then(
+    promises => {
+        console.log('resolve:', promises);
+    },
+    reason => {
+        console.log('reject:', reason);
+    }
+);

十二、实现Promise.race()

js
const p = Promise.race([p1, p2, p3]);
const p = Promise.race([p1, p2, p3]);

只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变;率先改变的 Promise 实例的返回值,就传递给p的回调函数。 (谁快用谁)

js
 static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }
 static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }

测试

js
 let p1 = new Promise(resolve => {
+        setInterval(() => {
+            resolve("成功1");
+        }, 1000);
+    });
+let p2 = new Promise(resolve => {
+    setInterval(() => {
+        resolve("成功2");
+    }, 500);
+});
+let promises = Promise.race([p1, p2]).then(
+    promises => {
+        console.log(promises);
+    },
+    reason => {
+        console.log(reason);
+    }
+);
 let p1 = new Promise(resolve => {
+        setInterval(() => {
+            resolve("成功1");
+        }, 1000);
+    });
+let p2 = new Promise(resolve => {
+    setInterval(() => {
+        resolve("成功2");
+    }, 500);
+});
+let promises = Promise.race([p1, p2]).then(
+    promises => {
+        console.log(promises);
+    },
+    reason => {
+        console.log(reason);
+    }
+);

十三、完整代码

js
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+
+    // 2.构造函数
+    constructor(executor) {
+        //初始态
+        this.status = Promise.PENDING
+        this.value = null
+        this.callbacks = []
+        // 绑定this    
+        try {
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        } catch (error) {
+
+        }
+
+    }
+    //3.resolve改变状态并执行回调函数
+    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                //遍历回调函数数组,传值并执行onFulfilled函数
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+  //3. reject改变状态并执行回调函数
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+             setTimeout(() => {
+                 //遍历回调函数数组,传值并执行onRejected函数
+            this.callbacks.map(callback => {
+                callback.onRejected(value);
+          	  });
+            });
+        }
+    }
+
+
+//then方法
+    then(onFulfilled, onRejected) {
+        //判断参数是否为函数
+        if (typeof onFulfilled != "function") {
+            onFulfilled = value => value;
+        }
+        if (typeof onRejected != "function") {
+            onRejected = value => value;
+        }
+        let promise = new Promise((resolve, reject) => {
+            //初始态把回调函数存入数组
+            if (this.status == Promise.PENDING) {
+                this.callbacks.push({
+                    onFulfilled: value => {
+                        this.parse(promise, onFulfilled(this.value), resolve, reject);
+                    },
+                    onRejected: value => {
+                        this.parse(promise, onRejected(this.value), resolve, reject);
+                    }
+                });
+            }
+            //成功
+            if (this.status == Promise.FULFILLED) {
+                setTimeout(() => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                });
+            }
+            //失败
+            if (this.status == Promise.REJECTED) {
+                setTimeout(() => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                });
+            }
+        });
+        //解决链式调用
+        return promise;
+    }
+    parse(promise, result, resolve, reject) {
+        //不能返回自身promise
+        if (promise == result) {
+            throw new TypeError("Chaining cycle detected for promise");
+        }
+        try {
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    }
+    static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }
+
+    static all(promises) {
+        let resolves = [];
+        return new Promise((resolve, reject) => {
+            //遍历每一个promise并执行
+            promises.forEach((promise, index) => {
+                promise.then(
+                    value => {
+                        resolves.push(value);//保存
+                        if (resolves.length == promises.length) {
+                            resolve(resolves);
+                        }
+                    },
+                    reason => {
+                        reject(reason);
+                    }
+                );
+            });
+        });
+    }
+    static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }
+}
class Promise {
+    // 1.定义三个状态
+    static PENDING = 'pending'
+    static FUFILLED = 'fulfilled'
+    static REJECTED = 'rejected'
+
+    // 2.构造函数
+    constructor(executor) {
+        //初始态
+        this.status = Promise.PENDING
+        this.value = null
+        this.callbacks = []
+        // 绑定this    
+        try {
+            executor(this.resolve.bind(this), this.reject.bind(this))
+        } catch (error) {
+
+        }
+
+    }
+    //3.resolve改变状态并执行回调函数
+    resolve(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.FULFILLED;
+            this.value = value;
+            setTimeout(() => {
+                //遍历回调函数数组,传值并执行onFulfilled函数
+                this.callbacks.map(callback => {
+                    callback.onFulfilled(value);
+                });
+            });
+        }
+    }
+  //3. reject改变状态并执行回调函数
+    reject(value) {
+        if (this.status == Promise.PENDING) {
+            this.status = Promise.REJECTED;
+            this.value = value;
+             setTimeout(() => {
+                 //遍历回调函数数组,传值并执行onRejected函数
+            this.callbacks.map(callback => {
+                callback.onRejected(value);
+          	  });
+            });
+        }
+    }
+
+
+//then方法
+    then(onFulfilled, onRejected) {
+        //判断参数是否为函数
+        if (typeof onFulfilled != "function") {
+            onFulfilled = value => value;
+        }
+        if (typeof onRejected != "function") {
+            onRejected = value => value;
+        }
+        let promise = new Promise((resolve, reject) => {
+            //初始态把回调函数存入数组
+            if (this.status == Promise.PENDING) {
+                this.callbacks.push({
+                    onFulfilled: value => {
+                        this.parse(promise, onFulfilled(this.value), resolve, reject);
+                    },
+                    onRejected: value => {
+                        this.parse(promise, onRejected(this.value), resolve, reject);
+                    }
+                });
+            }
+            //成功
+            if (this.status == Promise.FULFILLED) {
+                setTimeout(() => {
+                    this.parse(promise, onFulfilled(this.value), resolve, reject);
+                });
+            }
+            //失败
+            if (this.status == Promise.REJECTED) {
+                setTimeout(() => {
+                    this.parse(promise, onRejected(this.value), resolve, reject);
+                });
+            }
+        });
+        //解决链式调用
+        return promise;
+    }
+    parse(promise, result, resolve, reject) {
+        //不能返回自身promise
+        if (promise == result) {
+            throw new TypeError("Chaining cycle detected for promise");
+        }
+        try {
+            if (result instanceof Promise) {
+                result.then(resolve, reject);
+            } else {
+                resolve(result);
+            }
+        } catch (error) {
+            reject(error);
+        }
+    }
+    static resolve(value) {
+        return new Promise((resolve, reject) => {
+            if (value instanceof Promise) {
+                value.then(resolve, reject);
+            } else {
+                resolve(value);
+            }
+        });
+    }
+    static reject(reason) {
+        return new Promise((_, reject) => {
+            reject(reason);
+        });
+    }
+
+    static all(promises) {
+        let resolves = [];
+        return new Promise((resolve, reject) => {
+            //遍历每一个promise并执行
+            promises.forEach((promise, index) => {
+                promise.then(
+                    value => {
+                        resolves.push(value);//保存
+                        if (resolves.length == promises.length) {
+                            resolve(resolves);
+                        }
+                    },
+                    reason => {
+                        reject(reason);
+                    }
+                );
+            });
+        });
+    }
+    static race(promises) {
+        return new Promise((resolve, reject) => {
+            promises.map(promise => {
+                promise.then(value => {
+                    resolve(value);
+                });
+            });
+        });
+    }
+}
`,45),e=[o];function c(t,r,y,A,D,E){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.lean.js" "b/assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.lean.js" new file mode 100644 index 00000000..29ce3157 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\211\213\345\206\231Promise.md.fbddbbf5.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/手写Promise.md","filePath":"FrontEnd/JavaScript/手写Promise.md"}'),p={name:"FrontEnd/JavaScript/手写Promise.md"},o=l("",45),e=[o];function c(t,r,y,A,D,E){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.js" "b/assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.js" new file mode 100644 index 00000000..74109743 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.js" @@ -0,0 +1,529 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/数据去重.md","filePath":"FrontEnd/JavaScript/数据去重.md"}'),p={name:"FrontEnd/JavaScript/数据去重.md"},o=l(`

去重的核心:要根据实际业务怎么定义'重'

基本数据类型

js
const arr = [1, 2, 1, 3];
+//用Set去重
+const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
+//用filter去重
+const uniqueArr = arr => arr.filter((item, index) => arr.indexOf(item) === index); // 相同的元素只保留一个
+ 
+//indexOf
+const uniqueArr = (arr)  =>{
+   let newArr = [];
+  for (let i = 0; i < arr.length; i++) {
+    if (newArr.indexOf(arr[i]) === -1) {//或 !newArr.includes(arr[i])
+      newArr.push(arr[i]);
+    }
+  }
+  return newArr;
+}
+
+//==> reduce与 includes
+const uniqueArr = (arr)  => arr.reduce((newArr,item) => newArr.includes(item) ? newArr : [...newArr,item],[])
+
+//双重循环遍历数组去重
+const arr = [1, 2, 2, 3, 3, 3];
+const uniqueArr = [];
+for (let i = 0; i < arr.length; i++) {
+  let isDuplicate = false;
+  for (let j = 0; j < uniqueArr.length; j++) {
+    if (arr[i] === uniqueArr[j]) {
+      isDuplicate = true;
+      break;
+    }
+  }
+  if (!isDuplicate) {
+    uniqueArr.push(arr[i]);
+  }
+}
+console.log(uniqueArr); // [1, 2, 3]
const arr = [1, 2, 1, 3];
+//用Set去重
+const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
+//用filter去重
+const uniqueArr = arr => arr.filter((item, index) => arr.indexOf(item) === index); // 相同的元素只保留一个
+ 
+//indexOf
+const uniqueArr = (arr)  =>{
+   let newArr = [];
+  for (let i = 0; i < arr.length; i++) {
+    if (newArr.indexOf(arr[i]) === -1) {//或 !newArr.includes(arr[i])
+      newArr.push(arr[i]);
+    }
+  }
+  return newArr;
+}
+
+//==> reduce与 includes
+const uniqueArr = (arr)  => arr.reduce((newArr,item) => newArr.includes(item) ? newArr : [...newArr,item],[])
+
+//双重循环遍历数组去重
+const arr = [1, 2, 2, 3, 3, 3];
+const uniqueArr = [];
+for (let i = 0; i < arr.length; i++) {
+  let isDuplicate = false;
+  for (let j = 0; j < uniqueArr.length; j++) {
+    if (arr[i] === uniqueArr[j]) {
+      isDuplicate = true;
+      break;
+    }
+  }
+  if (!isDuplicate) {
+    uniqueArr.push(arr[i]);
+  }
+}
+console.log(uniqueArr); // [1, 2, 3]

如果要去重一个包含不同数据类型的数组,需要添加一些额外的检查。

Date类型转换成Unix时间戳,RegExp类型转换成字符串。

js
const arr = ["a", "b", 1, 1, "a", /abc/, /abc/, new Date(), new Date()];
+
+const isObject = val => Object(val) === val;//判断是否为对象
+const uniqueArr = (arr) =>[...new Set(arr.map(item => {
+ if (!isObject(item))  return item //不是
+    if (item instanceof Date) {
+      return item.getTime();
+    } else if (item instanceof RegExp) {
+      return item.toString();
+    }
+}))];
+ uniqueArr(arr); // ['a', 'b', 1, '/abc/', 1678519417983]
const arr = ["a", "b", 1, 1, "a", /abc/, /abc/, new Date(), new Date()];
+
+const isObject = val => Object(val) === val;//判断是否为对象
+const uniqueArr = (arr) =>[...new Set(arr.map(item => {
+ if (!isObject(item))  return item //不是
+    if (item instanceof Date) {
+      return item.getTime();
+    } else if (item instanceof RegExp) {
+      return item.toString();
+    }
+}))];
+ uniqueArr(arr); // ['a', 'b', 1, '/abc/', 1678519417983]

对象数组去重

对象相同比较

基本思路

  1. 首先判断两个值的类型是否相同,如果不同,则返回 false
  2. 处理特殊情况 null、undefined、Date、function
  3. 处理数组类型,对比项的数量,再递归对比每个项是否相等;
  4. 处理朴素对象,对比键的数量,相等则再递归对比值是否相等。
javascript
function isEqual(obj1, obj2) {
+  const equalType = (val1,val2) => Object.prototype.toString.call(val1)!== Object.prototype.toString.call(val2)
+  // 判断类型是否一致
+  if (equalType(obj1,obj2)) {
+    return false;
+  }
+
+  // 判断 null 和 undefined:只要有一个为 null 或 undefined,则直接比较值
+  if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
+    return obj1 === obj2;
+  }
+
+  // 判断基本类型是否相等
+  if (typeof obj1 === 'number' || typeof obj1 === 'string' || typeof obj1 === 'boolean') {
+    return obj1 === obj2;
+  }
+  if (typeof obj1 === "function" && typeof obj2 === "function") return obj1.toString() === obj2.toString();
+
+  if (obj1 instanceof Date && obj2 instanceof Date) return obj1.getTime() === obj2.getTime();
+
+  // 判断数组是否相等
+  if (Array.isArray(obj1)) {
+    if (!Array.isArray(obj2) || obj1.length !== obj2.length) {
+      return false;
+    }
+   return obj1.every((item,index) => isEqual(item, obj2[index]) )
+    // for (let i = 0; i < obj1.length; i++) {
+    //   if (!isEqual(obj1[i], obj2[i])) {
+    //     return false;
+    //   }
+    // }
+    // return true;
+  }
+  //比较对象是否相等
+  //Object.keys: 返回对象自身的所有可枚举的属性的键名,不包含 Symbol 类型键名
+  //Reflect.ownKeys(): 返回所有类型的键名,包括常规键名和 Symbol 键名。
+  const keys1 = Object.keys(obj1);
+  const keys2 = Object.keys(obj2);
+  if (keys1.length !== keys2.length) {
+    return false;
+  }
+  for (const key of keys1) {
+    if (!isEqual(obj1[key], obj2[key])) {
+      return false;
+    }
+  }
+  return true;
+}
function isEqual(obj1, obj2) {
+  const equalType = (val1,val2) => Object.prototype.toString.call(val1)!== Object.prototype.toString.call(val2)
+  // 判断类型是否一致
+  if (equalType(obj1,obj2)) {
+    return false;
+  }
+
+  // 判断 null 和 undefined:只要有一个为 null 或 undefined,则直接比较值
+  if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
+    return obj1 === obj2;
+  }
+
+  // 判断基本类型是否相等
+  if (typeof obj1 === 'number' || typeof obj1 === 'string' || typeof obj1 === 'boolean') {
+    return obj1 === obj2;
+  }
+  if (typeof obj1 === "function" && typeof obj2 === "function") return obj1.toString() === obj2.toString();
+
+  if (obj1 instanceof Date && obj2 instanceof Date) return obj1.getTime() === obj2.getTime();
+
+  // 判断数组是否相等
+  if (Array.isArray(obj1)) {
+    if (!Array.isArray(obj2) || obj1.length !== obj2.length) {
+      return false;
+    }
+   return obj1.every((item,index) => isEqual(item, obj2[index]) )
+    // for (let i = 0; i < obj1.length; i++) {
+    //   if (!isEqual(obj1[i], obj2[i])) {
+    //     return false;
+    //   }
+    // }
+    // return true;
+  }
+  //比较对象是否相等
+  //Object.keys: 返回对象自身的所有可枚举的属性的键名,不包含 Symbol 类型键名
+  //Reflect.ownKeys(): 返回所有类型的键名,包括常规键名和 Symbol 键名。
+  const keys1 = Object.keys(obj1);
+  const keys2 = Object.keys(obj2);
+  if (keys1.length !== keys2.length) {
+    return false;
+  }
+  for (const key of keys1) {
+    if (!isEqual(obj1[key], obj2[key])) {
+      return false;
+    }
+  }
+  return true;
+}
测试示例
js
// 示例
+const obj1 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj2 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj3 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+};
+isEqual(obj1, obj2) // true
+isEqual(obj1, obj3) // false
+isEqual(undefined, null)// false
+isEqual(null, null)
// 示例
+const obj1 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj2 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+};
+const obj3 = {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+};
+isEqual(obj1, obj2) // true
+isEqual(obj1, obj3) // false
+isEqual(undefined, null)// false
+isEqual(null, null)

对象数组去重

js

+const arr = [1,2,3,1]
+
+//深拷贝
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}
+
+const uniqueArr(arr){
+  const newArr = deepClone(arr)
+  let len = newArr.length
+  for(let i = 0; i < len; i++){
+    for(let j = i + 1; j < len; j++){
+      if(isEqual(newArr[i], newArr[j])){
+        newArr.splice(j,1)
+      }
+    }
+  }
+  return newArr
+}

+const arr = [1,2,3,1]
+
+//深拷贝
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}
+
+const uniqueArr(arr){
+  const newArr = deepClone(arr)
+  let len = newArr.length
+  for(let i = 0; i < len; i++){
+    for(let j = i + 1; j < len; j++){
+      if(isEqual(newArr[i], newArr[j])){
+        newArr.splice(j,1)
+      }
+    }
+  }
+  return newArr
+}
测试数据
js
let objArr1 = [
+  {a:1,b:2},
+  {a:2,b:3},
+  {b:2,a:1},
+  {a:3,b:2},
+  [1,2,3],
+  [4,5,6],
+  [2,1,3],
+  {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+     console.log(2)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-11'),
+    func:function(){
+     console.log(2)
+    }
+  }
+}
+]
+//uniqueArr(objArr1)
let objArr1 = [
+  {a:1,b:2},
+  {a:2,b:3},
+  {b:2,a:1},
+  {a:3,b:2},
+  [1,2,3],
+  [4,5,6],
+  [2,1,3],
+  {
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+      console.log(1)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    //date:new Date('2022-02-13'),
+    // func:function(){
+    //  console.log(1)
+    //}
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-13'),
+    func:function(){
+     console.log(2)
+    }
+  }
+},{
+  name: 'Tom',
+  age: 18,
+  hobby: ['reading', 'music','dance'],
+  address: {
+    province: 'Guangdong',
+    city: 'Shenzhen',
+    detail: {
+      street: 'Xinxi Road',
+      number: 888
+    },
+    date:new Date('2022-02-11'),
+    func:function(){
+     console.log(2)
+    }
+  }
+}
+]
+//uniqueArr(objArr1)
`,15),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.lean.js" "b/assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.lean.js" new file mode 100644 index 00000000..dab08fcf --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\225\260\346\215\256\345\216\273\351\207\215.md.f1eaba48.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/数据去重.md","filePath":"FrontEnd/JavaScript/数据去重.md"}'),p={name:"FrontEnd/JavaScript/数据去重.md"},o=l("",15),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.js" "b/assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.js" new file mode 100644 index 00000000..6bc05602 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.js" @@ -0,0 +1,159 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"JS常用的求交集、并集、差集的方法","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/数组求集合.md","filePath":"FrontEnd/JavaScript/数组求集合.md"}'),p={name:"FrontEnd/JavaScript/数组求集合.md"},o=l(`

JS常用的求交集、并集、差集的方法

普通数组

示例数组

js
let a = [1, 2, 3];
+let b = [4, 3, 2];
let a = [1, 2, 3];
+let b = [4, 3, 2];

一、并集(A∪B)

js
//方法一:
+;
+// 虽然 NaN 和 NaN 不相等,但是在 Set 集合里面只会存在一个
+// undefined 和 Infinity 在 Set 集合里面也只会存在一个
+let a = [1, 2, 3, NaN];
+let b = [2, 4, 5, NaN];
+const union  =  (arr1,arr2) => [...new Set([...arr1, ...arr2])]// [1, 2, 3, NaN, 4, 5]
+
+//方法二:
+const union = (arr1,arr2) =>  Array.from(new Set(arr1.concat(arr2)))
+
+//先b筛选a中没有的,再连接数组
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val => !arr1.includes(val)))
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val=> arr2.indexOf(val) === -1));
//方法一:
+;
+// 虽然 NaN 和 NaN 不相等,但是在 Set 集合里面只会存在一个
+// undefined 和 Infinity 在 Set 集合里面也只会存在一个
+let a = [1, 2, 3, NaN];
+let b = [2, 4, 5, NaN];
+const union  =  (arr1,arr2) => [...new Set([...arr1, ...arr2])]// [1, 2, 3, NaN, 4, 5]
+
+//方法二:
+const union = (arr1,arr2) =>  Array.from(new Set(arr1.concat(arr2)))
+
+//先b筛选a中没有的,再连接数组
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val => !arr1.includes(val)))
+const union = (arr1,arr2) => arr1.concat(arr2.filter(val=> arr2.indexOf(val) === -1));

二、交集(A∩B)

js
let intersection  = (arr1,arr2) => [...new Set(arr1.filter(val => arr2.includes(val)))];//[2, NaN]
let intersection  = (arr1,arr2) => [...new Set(arr1.filter(val => arr2.includes(val)))];//[2, NaN]

三、差集(A-B)

js
// 差集(a 相对于 b 的差集) 属于a不属于b的元素
+let difference  = (arr1,arr2) => [...new Set(arr1.filter(val => !arr2.includes(val)))];
+ 
+//返回a与b数组区别的集合(交集取反) 
+let a = [1, 2, 3];
+let b = [2, 4, 5];
+let difference = a.concat(b).filter(v => !a.includes(v) || !b.includes(v));
+let difference = a.concat(b).filter(v => !(a.includes(v) && b.includes(v)));
+console.log(difference)// [1,3,4,5]
+
+//方法二:先转为 Set
+let aSet = new Set(a);
+let bSet = new Set(b)
+//  
+let difference = Array.from(new Set(a.concat(b).filter(v => !aSet.has(v) || !bSet.has(v))));
+console.log(difference) // [1,3,4,5]
// 差集(a 相对于 b 的差集) 属于a不属于b的元素
+let difference  = (arr1,arr2) => [...new Set(arr1.filter(val => !arr2.includes(val)))];
+ 
+//返回a与b数组区别的集合(交集取反) 
+let a = [1, 2, 3];
+let b = [2, 4, 5];
+let difference = a.concat(b).filter(v => !a.includes(v) || !b.includes(v));
+let difference = a.concat(b).filter(v => !(a.includes(v) && b.includes(v)));
+console.log(difference)// [1,3,4,5]
+
+//方法二:先转为 Set
+let aSet = new Set(a);
+let bSet = new Set(b)
+//  
+let difference = Array.from(new Set(a.concat(b).filter(v => !aSet.has(v) || !bSet.has(v))));
+console.log(difference) // [1,3,4,5]

对象数组

示例数组

js
let a=[
+    {id:'01',name:'product01'},
+    {id:'02',name:'product02'},
+    {id:'03',name:'product03'},
+    {id:'04',name:'product04'},
+    {id:'05',name:'product05'}
+    ];
+let b=[
+    {id:'03',name:'product03'},
+    {id:'06',name:'product06'},
+    {id:'07',name:'product07'},
+    {id:'08',name:'product08'},
+
+];
let a=[
+    {id:'01',name:'product01'},
+    {id:'02',name:'product02'},
+    {id:'03',name:'product03'},
+    {id:'04',name:'product04'},
+    {id:'05',name:'product05'}
+    ];
+let b=[
+    {id:'03',name:'product03'},
+    {id:'06',name:'product06'},
+    {id:'07',name:'product07'},
+    {id:'08',name:'product08'},
+
+];

一、并集(A∪B)

js
// 用额外对象记录当前项 id 相同的是否收集,此 id 未收集,则进行收集
+//写法一:
+const union = (arr1,arr2) =>{
+    let obj = {};
+    let arr = arr1.concat(arr2);
+   return arr.reduce( (pre,cur) => {
+        if(!obj[cur.id]){
+            pre.push(cur)
+            obj[cur.id] = true
+        }
+        return pre
+    },[])
+}
+
+//写法二:
+const union = (arr1,arr2)=>{
+  let arr = arr1.concat(arr2)
+  let res = []
+  for(let i = 0; i < arr.length; i++){
+    if(res.findIndex(item => item.id === arr[i].id)===-1){
+      res.push(c[i])
+    }
+  }
+  return res
+}
+  //简化
+  //判断目标在数组中相同的 id 是否存在
+const isExist = (arr,target,attr) => arr.findIndex(item => item[attr] == target[attr]) != -1 
+//合并数组并遍历,判断新数组不存在当前项,则收集
+const union = (arr1,arr2) =>  arr1.concat(arr2).reduce((pre,cur) => isExist(pre,cur,'id') ? pre  : [...pre,cur],[])
// 用额外对象记录当前项 id 相同的是否收集,此 id 未收集,则进行收集
+//写法一:
+const union = (arr1,arr2) =>{
+    let obj = {};
+    let arr = arr1.concat(arr2);
+   return arr.reduce( (pre,cur) => {
+        if(!obj[cur.id]){
+            pre.push(cur)
+            obj[cur.id] = true
+        }
+        return pre
+    },[])
+}
+
+//写法二:
+const union = (arr1,arr2)=>{
+  let arr = arr1.concat(arr2)
+  let res = []
+  for(let i = 0; i < arr.length; i++){
+    if(res.findIndex(item => item.id === arr[i].id)===-1){
+      res.push(c[i])
+    }
+  }
+  return res
+}
+  //简化
+  //判断目标在数组中相同的 id 是否存在
+const isExist = (arr,target,attr) => arr.findIndex(item => item[attr] == target[attr]) != -1 
+//合并数组并遍历,判断新数组不存在当前项,则收集
+const union = (arr1,arr2) =>  arr1.concat(arr2).reduce((pre,cur) => isExist(pre,cur,'id') ? pre  : [...pre,cur],[])

二、交集(A∩B)

js
//方法一:
+const intersection = (arr1,arr2) => {
+    const aids = a.map(item => item.id)
+    return arr2.filter(item => aids.includes(item.id))
+}
+//方法二:
+const intersection = (arr1,arr2) =>  arr1.reduce((pre,cur) => arr2.findIndex(item => item.id == cur.id) != -1 ? [...pre,cur] : pre,[])
//方法一:
+const intersection = (arr1,arr2) => {
+    const aids = a.map(item => item.id)
+    return arr2.filter(item => aids.includes(item.id))
+}
+//方法二:
+const intersection = (arr1,arr2) =>  arr1.reduce((pre,cur) => arr2.findIndex(item => item.id == cur.id) != -1 ? [...pre,cur] : pre,[])

三、差集(A-B)

js
//找出arr1数组中,arr2数组没有的对象
+ const diff = (arr1, arr2) =>  arr1.filter(i => arr2.every(j => i.id !== j.id))
+ const diff = (arr1, arr2) =>  arr1.filter(i => !arr2.some(j => i.id === j.id))
//找出arr1数组中,arr2数组没有的对象
+ const diff = (arr1, arr2) =>  arr1.filter(i => arr2.every(j => i.id !== j.id))
+ const diff = (arr1, arr2) =>  arr1.filter(i => !arr2.some(j => i.id === j.id))
`,19),e=[o];function r(t,c,y,A,D,B){return a(),n("div",null,e)}const C=s(p,[["render",r]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.lean.js" "b/assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.lean.js" new file mode 100644 index 00000000..087ff397 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md.9e71e873.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"JS常用的求交集、并集、差集的方法","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/数组求集合.md","filePath":"FrontEnd/JavaScript/数组求集合.md"}'),p={name:"FrontEnd/JavaScript/数组求集合.md"},o=l("",19),e=[o];function r(t,c,y,A,D,B){return a(),n("div",null,e)}const C=s(p,[["render",r]]);export{i as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.js" "b/assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.js" new file mode 100644 index 00000000..f0239516 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.js" @@ -0,0 +1,171 @@ +import{D as x}from"./chunks/DemoWrap.1b6e7adf.js";import{d as g,a3 as w,h as D,o as C,c as d,k as n,a4 as u,a5 as F,F as U,_ as m,C as P,a as _,a6 as L,H as i,w as E,t as T,e as b,p as V,m as q,Q as f}from"./chunks/framework.c53372a0.js";const j=g({__name:"demo1",async setup(r){let l,t;const s=new Blob(["1,2,3"]),c=new File(["1,2,3"],"test.txt",{type:"text/plain"}),y=([l,t]=w(()=>s.arrayBuffer()),l=await l,t(),l);[l,t]=w(()=>c.arrayBuffer()),l=await l,t();const p=new FileReader;p.readAsArrayBuffer(c),p.onload=a=>{var B;console.log("[ e ]-11",(B=a.target)==null?void 0:B.result)},new DataView(y).setUint8(0,4);const o=D(null),e=a=>{o.value=a.target.files};return(a,B)=>(C(),d("input",{type:"file",onChange:e},null,32))}}),O={class:"opt-wrap"},H=g({__name:"FilePicker",setup(r){const l=async e=>{const a={title:"Open File",accept:{"image/*":[".png",".jpg",".jpeg"]}},[B]=await window.showOpenFilePicker(a),R=await B.getFile(),h=new FileReader;h.readAsArrayBuffer(R),h.onload=S=>{var v;console.log("[ e ]-11",(v=S.target)==null?void 0:v.result)}},t={title:"Open File",types:[{description:"Text Files",accept:{"text/plain":[".txt"]}}]},s=D("Hello World"),c=D(null),y=async()=>{const a=await(await window.showSaveFilePicker()).createWritable();await a.write(s.value),await a.close()},p=async()=>{const[e]=await window.showOpenFilePicker(t);c.value=e;const a=await e.getFile();s.value=await a.text()},A=async()=>{if(c.value){const e=await c.value.createWritable();await e.write(s.value),await e.close()}},o=()=>{y()};return(e,a)=>(C(),d(U,null,[n("input",{type:"file",onClick:l}),n("div",O,[u(n("textarea",{name:"",id:"",cols:"30",rows:"10","onUpdate:modelValue":a[0]||(a[0]=B=>s.value=B)},null,512),[[F,s.value]]),n("div",{class:"opts"},[n("button",{onClick:y}," 创建"),n("button",{onClick:p}," 打开"),n("button",{onClick:A},"保存 "),n("button",{onClick:o}," 保存为")])])],64))}});const I=m(H,[["__scopeId","data-v-6e6d96d1"]]),k=r=>(V("data-v-fcdef9a9"),r=r(),q(),r),N={class:"opt-wrap"},W=k(()=>n("option",{value:"BLOB"},"BLOB URL",-1)),z=k(()=>n("option",{value:"DATA"},"DATA URL",-1)),J=[W,z],$={key:0,class:"show-wrap"},M=["href"],Y=["src"],Q=["src"],G=g({__name:"DemoUrl",setup(r){const l=D("BLOB"),t=D(""),s=D(""),c=async(y,p)=>{t.value=y;const A=await fetch(p);if(l.value==="BLOB"){const o=await A.blob();s.value=URL.createObjectURL(o)}else{const o=new FileReader;o.onload=e=>{var a;s.value=(a=e.target)==null?void 0:a.result},o.readAsDataURL(await A.blob())}};return(y,p)=>{const A=P("font");return C(),d("div",null,[n("div",N,[_(" URL 类型"),u(n("select",{id:"urltype","onUpdate:modelValue":p[0]||(p[0]=o=>l.value=o)},J,512),[[L,l.value]]),n("button",{onClick:p[1]||(p[1]=o=>c("image","./demo/url.png"))},"获取图片 URL"),n("button",{onClick:p[2]||(p[2]=o=>c("text","./demo/url.txt"))},"获取文本 URL")]),u(n("textarea",{"onUpdate:modelValue":p[3]||(p[3]=o=>s.value=o)},null,512),[[F,s.value]]),s.value?(C(),d("div",$,[n("a",{href:s.value,target:"_blank"}," 链接 ",8,M),i(A,{color:"urlType=='DATA' ? 'red' :'green'"},{default:E(()=>[_("DATA URL"+T(l.value=="DATA"?"不":"")+"可直接点击链接打开, 可复制链接打开",1)]),_:1}),t.value=="image"?(C(),d("img",{key:0,src:s.value,alt:"图片"},null,8,Y)):b("",!0),n("iframe",{src:s.value},null,8,Q)])):b("",!0)])}}});const K=m(G,[["__scopeId","data-v-fcdef9a9"]]),X=f(`

Blob与 File

js
const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })
const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })

ArrayBuffer

js

+
+const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })
+
+//ArrayBuffer
+const blobArrayBuffer = await blob.arrayBuffer()
+const fileArrayBuffer = await file.arrayBuffer()
+
+console.log('[ blobArrayBuffer ]-6', blobArrayBuffer)
+console.log('[ fileArrayBuffer ]-8', fileArrayBuffer)

+
+const blob = new Blob(['1,2,3'])
+const file = new File(['1,2,3'], 'test.txt', { type: 'text/plain' })
+
+//ArrayBuffer
+const blobArrayBuffer = await blob.arrayBuffer()
+const fileArrayBuffer = await file.arrayBuffer()
+
+console.log('[ blobArrayBuffer ]-6', blobArrayBuffer)
+console.log('[ fileArrayBuffer ]-8', fileArrayBuffer)
`,4),Z=f(`

FileReader

js
const fileReader = new FileReader()
+fileReader.readAsArrayBuffer(file)
+fileReader.onload = (e) => {
+  console.log('[ e ]-13', e)
+  console.log('[ e.target ]-14', e.target)
+  console.log('[ e.target.result ]-15', e.target?.result  )
+  console.log( e.target?.result === fileArrayBuffer) // false
+}
const fileReader = new FileReader()
+fileReader.readAsArrayBuffer(file)
+fileReader.onload = (e) => {
+  console.log('[ e ]-13', e)
+  console.log('[ e.target ]-14', e.target)
+  console.log('[ e.target.result ]-15', e.target?.result  )
+  console.log( e.target?.result === fileArrayBuffer) // false
+}

2023-02-11-18-18-03

DataView

js
const dataView = new DataView(blobArrayBuffer)
+console.log('[ dataView ]-19', dataView)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
+dataView.setUint8(0, 4)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
const dataView = new DataView(blobArrayBuffer)
+console.log('[ dataView ]-19', dataView)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
+dataView.setUint8(0, 4)
+console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))

2023-02-11-18-25-32

FilePicker

js
const openFilePicker = async (e: any) => {
+   const option = {
+     title: 'Open File',
+     accept: {
+      'image/*': ['.png', '.jpg', '.jpeg'],
+     },
+   }
+    const [fileHandle] = await (window as any).showOpenFilePicker(option)
+    const file = await fileHandle.getFile()
+    const fileReader = new FileReader()
+    fileReader.readAsArrayBuffer(file)
+    fileReader.onload = (e) => {
+      console.log('[ e ]-11', e.target?.result)
+    }
+}
const openFilePicker = async (e: any) => {
+   const option = {
+     title: 'Open File',
+     accept: {
+      'image/*': ['.png', '.jpg', '.jpeg'],
+     },
+   }
+    const [fileHandle] = await (window as any).showOpenFilePicker(option)
+    const file = await fileHandle.getFile()
+    const fileReader = new FileReader()
+    fileReader.readAsArrayBuffer(file)
+    fileReader.onload = (e) => {
+      console.log('[ e ]-11', e.target?.result)
+    }
+}

文件操作

ts

+const textarea = ref('Hello World')
+const fh = ref(null)
+//创建文件
+const openCreate = async () => {
+  const  fileHandle  =  await  (window as any).showSaveFilePicker()
+  const fileSteam = await fileHandle.createWritable()
+  await fileSteam.write(textarea.value)
+  await fileSteam.close()
+}
+//打开文件
+const openShow = async () => {
+  const [ fileHandle ] =  await  (window as any).showOpenFilePicker(option)
+  fh.value = fileHandle
+  const file =  await  fileHandle.getFile()
+  textarea.value = await file.text()
+}
+//保存文件
+const openSave = async () => {
+  if(fh.value){
+    const fileSteam = await fh.value.createWritable()
+    await fileSteam.write(textarea.value)
+    await fileSteam.close()
+  }
+}
+//保存为文件
+const openSaveAs = () => {
+  openCreate()
+}

+const textarea = ref('Hello World')
+const fh = ref(null)
+//创建文件
+const openCreate = async () => {
+  const  fileHandle  =  await  (window as any).showSaveFilePicker()
+  const fileSteam = await fileHandle.createWritable()
+  await fileSteam.write(textarea.value)
+  await fileSteam.close()
+}
+//打开文件
+const openShow = async () => {
+  const [ fileHandle ] =  await  (window as any).showOpenFilePicker(option)
+  fh.value = fileHandle
+  const file =  await  fileHandle.getFile()
+  textarea.value = await file.text()
+}
+//保存文件
+const openSave = async () => {
+  if(fh.value){
+    const fileSteam = await fh.value.createWritable()
+    await fileSteam.write(textarea.value)
+    await fileSteam.close()
+  }
+}
+//保存为文件
+const openSaveAs = () => {
+  openCreate()
+}

filepicker

`,11),ss=f(`

URL

js
//Blob URL
+URL.createObjectURL(blob) 
+
+//Data  URL
+FileReader.readAsDataURL(file)  
+canvas.toDataURL()
//Blob URL
+URL.createObjectURL(blob) 
+
+//Data  URL
+FileReader.readAsDataURL(file)  
+canvas.toDataURL()
vue
<a :href="url">   </a> 
+<img :src="url" />
+<iframe :src="url"></iframe>
<a :href="url">   </a> 
+<img :src="url" />
+<iframe :src="url"></iframe>
ts
type TYPE = 'text' | 'image' | ''
+const url = ref<string>('')
+const onFetch = async (type: TYPE, path: string) => {
+  const response = await fetch(path)
+  //BLOB URL
+  // const data = await response.blob()
+  // url.value = URL.createObjectURL(data)
+
+  //Data URL
+  const fr = new FileReader()
+  fr.onload = (e) => {
+    url.value = e.target?.result as string
+  }
+  fr.readAsDataURL(await response.blob())
+}
type TYPE = 'text' | 'image' | ''
+const url = ref<string>('')
+const onFetch = async (type: TYPE, path: string) => {
+  const response = await fetch(path)
+  //BLOB URL
+  // const data = await response.blob()
+  // url.value = URL.createObjectURL(data)
+
+  //Data URL
+  const fr = new FileReader()
+  fr.onload = (e) => {
+    url.value = e.target?.result as string
+  }
+  fr.readAsDataURL(await response.blob())
+}
`,4),as=f('

参考资料

MDN Blob API 参考
MDN File API 参考
谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64

',2),os=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/文件系统.md","filePath":"FrontEnd/JavaScript/文件系统.md"}'),ns={name:"FrontEnd/JavaScript/文件系统.md"},es=Object.assign(ns,{setup(r){return(l,t)=>{const s=x;return C(),d("div",null,[X,i(s,{pkg:"FrontEnd/JavaScript/demo",path:"demo1.vue"},{default:E(()=>[i(j)]),_:1}),Z,i(s,{pkg:"FrontEnd/JavaScript/demo",path:"FilePicker.vue"},{default:E(()=>[i(I)]),_:1}),ss,i(s,{pkg:"FrontEnd/JavaScript/demo",path:"DemoUrl.vue"},{default:E(()=>[i(K)]),_:1}),as])}}});export{os as __pageData,es as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.lean.js" "b/assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.lean.js" new file mode 100644 index 00000000..59294714 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\226\207\344\273\266\347\263\273\347\273\237.md.1488f287.lean.js" @@ -0,0 +1 @@ +import{D as x}from"./chunks/DemoWrap.1b6e7adf.js";import{d as g,a3 as w,h as D,o as C,c as d,k as n,a4 as u,a5 as F,F as U,_ as m,C as P,a as _,a6 as L,H as i,w as E,t as T,e as b,p as V,m as q,Q as f}from"./chunks/framework.c53372a0.js";const j=g({__name:"demo1",async setup(r){let l,t;const s=new Blob(["1,2,3"]),c=new File(["1,2,3"],"test.txt",{type:"text/plain"}),y=([l,t]=w(()=>s.arrayBuffer()),l=await l,t(),l);[l,t]=w(()=>c.arrayBuffer()),l=await l,t();const p=new FileReader;p.readAsArrayBuffer(c),p.onload=a=>{var B;console.log("[ e ]-11",(B=a.target)==null?void 0:B.result)},new DataView(y).setUint8(0,4);const o=D(null),e=a=>{o.value=a.target.files};return(a,B)=>(C(),d("input",{type:"file",onChange:e},null,32))}}),O={class:"opt-wrap"},H=g({__name:"FilePicker",setup(r){const l=async e=>{const a={title:"Open File",accept:{"image/*":[".png",".jpg",".jpeg"]}},[B]=await window.showOpenFilePicker(a),R=await B.getFile(),h=new FileReader;h.readAsArrayBuffer(R),h.onload=S=>{var v;console.log("[ e ]-11",(v=S.target)==null?void 0:v.result)}},t={title:"Open File",types:[{description:"Text Files",accept:{"text/plain":[".txt"]}}]},s=D("Hello World"),c=D(null),y=async()=>{const a=await(await window.showSaveFilePicker()).createWritable();await a.write(s.value),await a.close()},p=async()=>{const[e]=await window.showOpenFilePicker(t);c.value=e;const a=await e.getFile();s.value=await a.text()},A=async()=>{if(c.value){const e=await c.value.createWritable();await e.write(s.value),await e.close()}},o=()=>{y()};return(e,a)=>(C(),d(U,null,[n("input",{type:"file",onClick:l}),n("div",O,[u(n("textarea",{name:"",id:"",cols:"30",rows:"10","onUpdate:modelValue":a[0]||(a[0]=B=>s.value=B)},null,512),[[F,s.value]]),n("div",{class:"opts"},[n("button",{onClick:y}," 创建"),n("button",{onClick:p}," 打开"),n("button",{onClick:A},"保存 "),n("button",{onClick:o}," 保存为")])])],64))}});const I=m(H,[["__scopeId","data-v-6e6d96d1"]]),k=r=>(V("data-v-fcdef9a9"),r=r(),q(),r),N={class:"opt-wrap"},W=k(()=>n("option",{value:"BLOB"},"BLOB URL",-1)),z=k(()=>n("option",{value:"DATA"},"DATA URL",-1)),J=[W,z],$={key:0,class:"show-wrap"},M=["href"],Y=["src"],Q=["src"],G=g({__name:"DemoUrl",setup(r){const l=D("BLOB"),t=D(""),s=D(""),c=async(y,p)=>{t.value=y;const A=await fetch(p);if(l.value==="BLOB"){const o=await A.blob();s.value=URL.createObjectURL(o)}else{const o=new FileReader;o.onload=e=>{var a;s.value=(a=e.target)==null?void 0:a.result},o.readAsDataURL(await A.blob())}};return(y,p)=>{const A=P("font");return C(),d("div",null,[n("div",N,[_(" URL 类型"),u(n("select",{id:"urltype","onUpdate:modelValue":p[0]||(p[0]=o=>l.value=o)},J,512),[[L,l.value]]),n("button",{onClick:p[1]||(p[1]=o=>c("image","./demo/url.png"))},"获取图片 URL"),n("button",{onClick:p[2]||(p[2]=o=>c("text","./demo/url.txt"))},"获取文本 URL")]),u(n("textarea",{"onUpdate:modelValue":p[3]||(p[3]=o=>s.value=o)},null,512),[[F,s.value]]),s.value?(C(),d("div",$,[n("a",{href:s.value,target:"_blank"}," 链接 ",8,M),i(A,{color:"urlType=='DATA' ? 'red' :'green'"},{default:E(()=>[_("DATA URL"+T(l.value=="DATA"?"不":"")+"可直接点击链接打开, 可复制链接打开",1)]),_:1}),t.value=="image"?(C(),d("img",{key:0,src:s.value,alt:"图片"},null,8,Y)):b("",!0),n("iframe",{src:s.value},null,8,Q)])):b("",!0)])}}});const K=m(G,[["__scopeId","data-v-fcdef9a9"]]),X=f("",4),Z=f("",11),ss=f("",4),as=f("",2),os=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/文件系统.md","filePath":"FrontEnd/JavaScript/文件系统.md"}'),ns={name:"FrontEnd/JavaScript/文件系统.md"},es=Object.assign(ns,{setup(r){return(l,t)=>{const s=x;return C(),d("div",null,[X,i(s,{pkg:"FrontEnd/JavaScript/demo",path:"demo1.vue"},{default:E(()=>[i(j)]),_:1}),Z,i(s,{pkg:"FrontEnd/JavaScript/demo",path:"FilePicker.vue"},{default:E(()=>[i(I)]),_:1}),ss,i(s,{pkg:"FrontEnd/JavaScript/demo",path:"DemoUrl.vue"},{default:E(()=>[i(K)]),_:1}),as])}}});export{os as __pageData,es as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.js" "b/assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.js" new file mode 100644 index 00000000..82b5ecc9 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.js" @@ -0,0 +1,237 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/正则表达式.md","filePath":"FrontEnd/JavaScript/正则表达式.md"}'),p={name:"FrontEnd/JavaScript/正则表达式.md"},o=l(`

资料参考:LearnRegex

应用场景

  1. 表单校验
  2. 字符串匹配和替换、解析(vue模板解析)

可视化工具:

  1. Regulex
  2. Regexper

1. 或者 |

javascript
let tel = "020-99999999"
+console.log(/(010|020)\\-\\d{8}/.test(tel));//true
let tel = "020-99999999"
+console.log(/(010|020)\\-\\d{8}/.test(tel));//true

2. 原子表[]、原子组()

javascript
//原子表
+let reg = /[123456]/ //出现在其中就匹配成功
+console.log(reg.test("2")) //true
+console.log(reg.test("9")) //false
+
+//[()] [.+] 特殊符号放在原子表里就是普通符号(保留字符本意)
+let str = 'www.baidu.com+'
+console.log(str.match(/[.+]/gi)) //['.', '.', '+']
+
+//原子组
+let reg = /(34|56)/
+console.log(reg.test("hdjfaks34fjj")) //true 满足组合才行
+console.log(reg.test("hdjfaks35fjj")) //false
//原子表
+let reg = /[123456]/ //出现在其中就匹配成功
+console.log(reg.test("2")) //true
+console.log(reg.test("9")) //false
+
+//[()] [.+] 特殊符号放在原子表里就是普通符号(保留字符本意)
+let str = 'www.baidu.com+'
+console.log(str.match(/[.+]/gi)) //['.', '.', '+']
+
+//原子组
+let reg = /(34|56)/
+console.log(reg.test("hdjfaks34fjj")) //true 满足组合才行
+console.log(reg.test("hdjfaks35fjj")) //false

3. 边界符^$

javascript
let tel = "12020-99999999"
+console.log(/^(010|020)\\-\\d{8}/.test(tel));//false 以010开头
+
+let tel = "020-999999998"
+console.log(/^(010|020)\\-\\d{8}$/.test(tel));//false 以8位数结尾
let tel = "12020-99999999"
+console.log(/^(010|020)\\-\\d{8}/.test(tel));//false 以010开头
+
+let tel = "020-999999998"
+console.log(/^(010|020)\\-\\d{8}$/.test(tel));//false 以8位数结尾

4. 元字符

image.png

5. 匹配所有字符

javascript
/[\\s\\S]/  
+/[\\d\\D]/
/[\\s\\S]/  
+/[\\d\\D]/

6. 模式修正符号ig

javascript
let hd = 'djfkdjakDJFKJD'
+hd.match(/[a-z]/ig)
+//i 不区分大小写
+//g 全局匹配
+//m 每一行单独处理(^,$)检测字符串的开头或结尾,如果想要它在每行的开头和结尾生效,则用m
+//u 宽字节匹配
+//y 匹配完不匹配后面(提升效率)
+//字符属性
+let hdstr = \`dfa2332,hello! 正则表达式,哈!\`
+hdstr.match(/\\p{sc=Han}/gu) //按语言系统匹配中文 ['正', '则', '表', '达', '式',  '哈']
+hdstr.match(/\\p{P}/gu) //匹配所有标点符号  //[',', '!', ',', '!']
+hdstr.match(/\\p{L}/gu) //匹配所有字母
let hd = 'djfkdjakDJFKJD'
+hd.match(/[a-z]/ig)
+//i 不区分大小写
+//g 全局匹配
+//m 每一行单独处理(^,$)检测字符串的开头或结尾,如果想要它在每行的开头和结尾生效,则用m
+//u 宽字节匹配
+//y 匹配完不匹配后面(提升效率)
+//字符属性
+let hdstr = \`dfa2332,hello! 正则表达式,哈!\`
+hdstr.match(/\\p{sc=Han}/gu) //按语言系统匹配中文 ['正', '则', '表', '达', '式',  '哈']
+hdstr.match(/\\p{P}/gu) //匹配所有标点符号  //[',', '!', ',', '!']
+hdstr.match(/\\p{L}/gu) //匹配所有字母

7. 原子组中的原子表([-\\/])

javascript
let dateStr = '2022-08-30'   '2022/08/30'//true 
+let reg = /^\\d{4}([-\\/])\\d{2}\\1\\d{2}/
+console.log(reg.test('2022-08/30') //false
+
+let reg1 = /^[a-z]\\w{3,7}$/gi //校验用户名
+
+
+let hhtml = \`<h1>www.baidu.com</h1>
+<h2>www.sougou.com</h2>\`
+let reg = /<(h[1-6])>([\\s\\S]*)<\\/\\1>/i;
+[
+    "<h1>www.baidu.com</h1>", //匹配到的第一个
+    "h1", //原子组1   
+    "www.baidu.com" //原子组2
+]
+
+//替换操作
+let res = hhtml.replace(reg,\`<p>$1</p>\`)
+let res = hhtml.replace(reg,(p0,p1,p2)=>\`<p>\${p1}</p>\`
+                        
+$& //找到内容本身 (\\0)
+$\` //内容前面的字符
+$' //内容后面的字符
+
+let reg = /<(h[1-6])>([\\s\\S]*)<\\/\\1>/gi; //全局匹配
+[
+    "<h1>www.baidu.com</h1>",
+    "<h2>www.sougou.com</h2>"
+]
+
+let mailReg =  /^\\w[\\w-]+@[\\w]([\\w-]+.)+(com|cn|cc|net|org)/
+
+
+//不记录分组(?:) 原子组中使用?:则(match,exec输出结果中)不会记录此原子组
let dateStr = '2022-08-30'   '2022/08/30'//true 
+let reg = /^\\d{4}([-\\/])\\d{2}\\1\\d{2}/
+console.log(reg.test('2022-08/30') //false
+
+let reg1 = /^[a-z]\\w{3,7}$/gi //校验用户名
+
+
+let hhtml = \`<h1>www.baidu.com</h1>
+<h2>www.sougou.com</h2>\`
+let reg = /<(h[1-6])>([\\s\\S]*)<\\/\\1>/i;
+[
+    "<h1>www.baidu.com</h1>", //匹配到的第一个
+    "h1", //原子组1   
+    "www.baidu.com" //原子组2
+]
+
+//替换操作
+let res = hhtml.replace(reg,\`<p>$1</p>\`)
+let res = hhtml.replace(reg,(p0,p1,p2)=>\`<p>\${p1}</p>\`
+                        
+$& //找到内容本身 (\\0)
+$\` //内容前面的字符
+$' //内容后面的字符
+
+let reg = /<(h[1-6])>([\\s\\S]*)<\\/\\1>/gi; //全局匹配
+[
+    "<h1>www.baidu.com</h1>",
+    "<h2>www.sougou.com</h2>"
+]
+
+let mailReg =  /^\\w[\\w-]+@[\\w]([\\w-]+.)+(com|cn|cc|net|org)/
+
+
+//不记录分组(?:) 原子组中使用?:则(match,exec输出结果中)不会记录此原子组

8.贪婪匹配+*?

javascript
+ //一个或多个
+* //0个或多个
+? //0个或1个
+{0,10} //0-10个
+
+//禁止贪婪(往少的一方倾斜)
++? //一个 let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+*? //匹配到一个就停止let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+?? // let reg = /(.??at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['fat']
+{3,}?  {3,10}? //3个
+
+  //案例练习
+let html= \`<span>www.baidu.com</span>
+<span>www.map.baidu.com</span>
+<span>www.know.baidu.com</span>\`
+let regbaidu = /<span>[\\s\\S]+<\\/span>/ //贪婪到最后
+let regbaidu1 = /<span>([\\s\\S]+?)<\\/span>/gi
+let newhtml= html.replace(regbaidu1,(v,p1)=> \`<h2 style='color:red'>\${p1}</h2>\`)
+//"<h2 style='color:red'>www.baidu.com</h2>\\n<h2 style='color:red'>www.map.baidu.com</h2>\\n<h2 style='color:red'>www.know.baidu.com</h2>"
+ //一个或多个
+* //0个或多个
+? //0个或1个
+{0,10} //0-10个
+
+//禁止贪婪(往少的一方倾斜)
++? //一个 let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+*? //匹配到一个就停止let reg = /(.*?at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['The fat']
+?? // let reg = /(.??at)/ ==> 'The fat cat sat on the mat. '.match(reg) ['fat']
+{3,}?  {3,10}? //3个
+
+  //案例练习
+let html= \`<span>www.baidu.com</span>
+<span>www.map.baidu.com</span>
+<span>www.know.baidu.com</span>\`
+let regbaidu = /<span>[\\s\\S]+<\\/span>/ //贪婪到最后
+let regbaidu1 = /<span>([\\s\\S]+?)<\\/span>/gi
+let newhtml= html.replace(regbaidu1,(v,p1)=> \`<h2 style='color:red'>\${p1}</h2>\`)
+//"<h2 style='color:red'>www.baidu.com</h2>\\n<h2 style='color:red'>www.map.baidu.com</h2>\\n<h2 style='color:red'>www.know.baidu.com</h2>"

批量验证密码

javascript
let psdRegs = [/^[0-9a-z]{6,10}$/i,/[A-Z]/,/[0-9]/]
+let result = psdRegs.every(reg => reg.test('fdkafad')) //false
+let result = psdRegs.every(reg => reg.test('1f12aA'))  //true
let psdRegs = [/^[0-9a-z]{6,10}$/i,/[A-Z]/,/[0-9]/]
+let result = psdRegs.every(reg => reg.test('fdkafad')) //false
+let result = psdRegs.every(reg => reg.test('1f12aA'))  //true

9. matchAll

javascript
let hstr = \`<h1>www.baidu.com</h1>
+<h2>www.map.baidu.com</h2>
+<h3>百度一下</h3>\`
+let breg = /<(h[1-6])>([\\S\\s]+)<\\/\\1>/gi
+
+hstr.match(breg) //全局匹配拿不到它每个原子组
+['<h1>www.baidu.com</h1>', '<h2>www.map.baidu.com</h2>', '<h3>百度一下</h3>']
+
+//解决方法:使用matchAll
+for(it of hstr.matchAll(breg)){ 
+  console.dir(it);
+  content.push(it[2]);
+}
+//每个匹配项信息
+[
+    "<h1>www.baidu.com</h1>",
+    "h1",  //原子组1
+    "www.baidu.com" //原子组2
+]
let hstr = \`<h1>www.baidu.com</h1>
+<h2>www.map.baidu.com</h2>
+<h3>百度一下</h3>\`
+let breg = /<(h[1-6])>([\\S\\s]+)<\\/\\1>/gi
+
+hstr.match(breg) //全局匹配拿不到它每个原子组
+['<h1>www.baidu.com</h1>', '<h2>www.map.baidu.com</h2>', '<h3>百度一下</h3>']
+
+//解决方法:使用matchAll
+for(it of hstr.matchAll(breg)){ 
+  console.dir(it);
+  content.push(it[2]);
+}
+//每个匹配项信息
+[
+    "<h1>www.baidu.com</h1>",
+    "h1",  //原子组1
+    "www.baidu.com" //原子组2
+]

image.png

10. 断言匹配\`\`

javascript
let reg = /百度(?=地图)/g
+// 只有百度后面有地图两字的才满足要求
+let htm = <p>百度一下,百度地图</p>
+p.innerHTML.replace(reg,\`<a href="www.map.baidu.com">$&</a>\`)
+
+?= //判断 
+
+?<= //判断前面内容是..
+?<=href= //前面是href="www.baidu.com"符合
+
+?! //限制不是..
+let reg =  /[a-z]+(?!\\d)$/i  //限制最后一位不是数字
+
+?! //限定不包含关键词,必须以字母结束
+let reg = /^(?!.*百度.*)[a-z]{4,5}$/i
+
+?<! //前面不是数字 
+let reg = /(?<!\\d+)[a-z]+/i
+'baidu88baidu'.match(reg) //baidu
let reg = /百度(?=地图)/g
+// 只有百度后面有地图两字的才满足要求
+let htm = <p>百度一下,百度地图</p>
+p.innerHTML.replace(reg,\`<a href="www.map.baidu.com">$&</a>\`)
+
+?= //判断 
+
+?<= //判断前面内容是..
+?<=href= //前面是href="www.baidu.com"符合
+
+?! //限制不是..
+let reg =  /[a-z]+(?!\\d)$/i  //限制最后一位不是数字
+
+?! //限定不包含关键词,必须以字母结束
+let reg = /^(?!.*百度.*)[a-z]{4,5}$/i
+
+?<! //前面不是数字 
+let reg = /(?<!\\d+)[a-z]+/i
+'baidu88baidu'.match(reg) //baidu

将链接替换为想要的网址

image.png

将不含oss的替换

image.png

模糊电话后四位

image.png

案例练习

替换练习

image.png

给原子组起别名

image.png

`,39),e=[o];function t(c,r,y,A,D,B){return a(),n("div",null,e)}const h=s(p,[["render",t]]);export{C as __pageData,h as default}; diff --git "a/assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.lean.js" "b/assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.lean.js" new file mode 100644 index 00000000..b48ff19c --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.a9560fb8.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/正则表达式.md","filePath":"FrontEnd/JavaScript/正则表达式.md"}'),p={name:"FrontEnd/JavaScript/正则表达式.md"},o=l("",39),e=[o];function t(c,r,y,A,D,B){return a(),n("div",null,e)}const h=s(p,[["render",t]]);export{C as __pageData,h as default}; diff --git "a/assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.js" "b/assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.js" new file mode 100644 index 00000000..242d622f --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.js" @@ -0,0 +1,89 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"获取目录结构(纯前端)","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/获取目录结构.md","filePath":"FrontEnd/JavaScript/获取目录结构.md"}'),p={name:"FrontEnd/JavaScript/获取目录结构.md"},o=l(`

获取目录结构(纯前端)

vue
 <button @click="onSelectDir" class="select-btn">选择文件夹</button>
 <button @click="onSelectDir" class="select-btn">选择文件夹</button>
js
const onSelectDir = async () => {
+  const dirHandle = await window.showDirectoryPicker()
+  await getDirData(dirHandle, directoryData)
+}
+/*递归获取文件夹下的所有文件, 并生成树状结构 
+ {
+"id": "o6ukw45e",
+"name": "core",
+"ftype": "dir",
+"children": [
+  {
+    "id": "bc41wb16",
+    "name": ".eslintrc.cjs",
+    "ftype": "cjs"
+  },]
+}
+*/
+let exclude = ["node_modules", ".git", ".vscode", ".prettierignore", "dist"]; //排除的文件夹
+const getDirData = async (dirHandle, dirData) => {
+  for await (const entry of dirHandle.values()) {
+    let { name, kind } = entry
+    //文件大小
+    if (kind === 'file') {
+      const size = await entry.getFile().then(file => file.size || 0)
+      const ftype = name.split('.').length > 1 ? name.split('.')[1] : 'unknown'
+      dirData.children.push({
+        id: randomId(),
+        name,
+        size,
+        value: size,
+        ftype
+      })
+    } else if (kind === 'directory') {
+      if (exclude.includes(name)) continue;
+      const children = {
+        id: randomId(),
+        name,
+        ftype: 'dir',
+        children: []
+      }
+      dirData.children.push(children)
+      await getDirData(entry, children)
+    }
+  }
+}
const onSelectDir = async () => {
+  const dirHandle = await window.showDirectoryPicker()
+  await getDirData(dirHandle, directoryData)
+}
+/*递归获取文件夹下的所有文件, 并生成树状结构 
+ {
+"id": "o6ukw45e",
+"name": "core",
+"ftype": "dir",
+"children": [
+  {
+    "id": "bc41wb16",
+    "name": ".eslintrc.cjs",
+    "ftype": "cjs"
+  },]
+}
+*/
+let exclude = ["node_modules", ".git", ".vscode", ".prettierignore", "dist"]; //排除的文件夹
+const getDirData = async (dirHandle, dirData) => {
+  for await (const entry of dirHandle.values()) {
+    let { name, kind } = entry
+    //文件大小
+    if (kind === 'file') {
+      const size = await entry.getFile().then(file => file.size || 0)
+      const ftype = name.split('.').length > 1 ? name.split('.')[1] : 'unknown'
+      dirData.children.push({
+        id: randomId(),
+        name,
+        size,
+        value: size,
+        ftype
+      })
+    } else if (kind === 'directory') {
+      if (exclude.includes(name)) continue;
+      const children = {
+        id: randomId(),
+        name,
+        ftype: 'dir',
+        children: []
+      }
+      dirData.children.push(children)
+      await getDirData(entry, children)
+    }
+  }
+}
`,3),e=[o];function t(c,r,y,D,A,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.lean.js" "b/assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.lean.js" new file mode 100644 index 00000000..f27069e8 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\350\216\267\345\217\226\347\233\256\345\275\225\347\273\223\346\236\204.md.f15b6a8f.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"获取目录结构(纯前端)","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/获取目录结构.md","filePath":"FrontEnd/JavaScript/获取目录结构.md"}'),p={name:"FrontEnd/JavaScript/获取目录结构.md"},o=l("",3),e=[o];function t(c,r,y,D,A,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.js" "b/assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.js" new file mode 100644 index 00000000..5bad9437 --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.js" @@ -0,0 +1,293 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/高阶函数.md","filePath":"FrontEnd/JavaScript/高阶函数.md"}'),p={name:"FrontEnd/JavaScript/高阶函数.md"},o=l(`

高阶函数之filter

定义

  • 通过提供函数实现的依次测试的所有元素,true 则表示通过,如果为 false 则失败。
  • 返回值是一个新数组,由通过测试为 true 的所有元素组成
  • 如果没有任何数组元素通过测试,则返回空数组。

TIP

  1. 原始数组不发生改变
  2. 不会对空数组进行检测
  3. 满足条件的留下,是对原数组的过滤。

语法

js
array.filter(function(currentValue,index,arr), thisValue)
+//currentValue  必须,遍历到的当前元素值
+//index         可选,当前元素的索引值
+//arr           可选,当前元素属于的数组对象
array.filter(function(currentValue,index,arr), thisValue)
+//currentValue  必须,遍历到的当前元素值
+//index         可选,当前元素的索引值
+//arr           可选,当前元素属于的数组对象

用法

过滤小于 100
javascript
const nums = [20,30,110,60,190,50]
+let newNums =nums.filter(n =>{
+  return n < 100
+})
+console.log(newNums)//[20,30,60,50]
const nums = [20,30,110,60,190,50]
+let newNums =nums.filter(n =>{
+  return n < 100
+})
+console.log(newNums)//[20,30,60,50]
返回奇数元素
js
var arr=[1,2,3,4,5,6];
+let res = arr.filter(function(x){
+    return x%2!==0;
+})
+console.log(res)//[1,3,5]
var arr=[1,2,3,4,5,6];
+let res = arr.filter(function(x){
+    return x%2!==0;
+})
+console.log(res)//[1,3,5]
数组去重
js
var  arr= ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
+
+//去除重复元素依靠的是indexOf总是返回第一个元素的位置,
+//后续的重复元素位置与indexOf返回的位置相等,表示是同一个元素
+//后续的重复元素位置与indexOf返回的位置不相等,表示元素重复并且过滤。
+var filterArr = arr.filter((value,index,arr) => arr.indexOf(value)===index;)
+console.log(filterArr);//["apple", "strawberry", "banana", "pear", "orange"]
var  arr= ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
+
+//去除重复元素依靠的是indexOf总是返回第一个元素的位置,
+//后续的重复元素位置与indexOf返回的位置相等,表示是同一个元素
+//后续的重复元素位置与indexOf返回的位置不相等,表示元素重复并且过滤。
+var filterArr = arr.filter((value,index,arr) => arr.indexOf(value)===index;)
+console.log(filterArr);//["apple", "strawberry", "banana", "pear", "orange"]
js
const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
+const arr2 = arr1.filter( (element, index, self) => {
+    return self.indexOf( element ) === index;
+});
+
+console.log( arr2 );
+// [1, 2, 3, 5, 4]
+console.log( arr1 );
+// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]
const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
+const arr2 = arr1.filter( (element, index, self) => {
+    return self.indexOf( element ) === index;
+});
+
+console.log( arr2 );
+// [1, 2, 3, 5, 4]
+console.log( arr1 );
+// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]
找出素数
js
//除了1和自身,不能被其他数整除的
+var arr=[1,2,3,4,5,6,7,8,9,11,20,37];
+const result = arr.filter(value => {
+	if(value == 1) return false;
+ 	if(value == 2) return true; 
+    for(var i = 2; i < Math.sqrt(value) + 1; i++){
+      if(value % i == 0)  return false;
+    }
+     return true;
+ });
//除了1和自身,不能被其他数整除的
+var arr=[1,2,3,4,5,6,7,8,9,11,20,37];
+const result = arr.filter(value => {
+	if(value == 1) return false;
+ 	if(value == 2) return true; 
+    for(var i = 2; i < Math.sqrt(value) + 1; i++){
+      if(value % i == 0)  return false;
+    }
+     return true;
+ });

高阶函数之map

定义

原数组中的每个元素依次调用一个指定方法后,

返回值组成的新数组

TIP

  1. 原始数组不发生改变
  2. 不会对空数组进行检测
  3. 对原数组的加工,返回加工后新数组

语法

js
array.map(function(currentValue,index,arr), thisValue)
+//currentValue  数组中正在处理的当前元素。
+//index可选  数组中正在处理的当前元素的索引。
+//array可选  map 方法被调用的数组。
+//thisArg可选 执行 callback 函数时使用的this 值。
array.map(function(currentValue,index,arr), thisValue)
+//currentValue  数组中正在处理的当前元素。
+//index可选  数组中正在处理的当前元素的索引。
+//array可选  map 方法被调用的数组。
+//thisArg可选 执行 callback 函数时使用的this 值。

用法

返回数组元素平方后的新数组
js
function pow(x){  //定义一个平方函数
+    return x*x;
+}
+
+var arr=[1,2,3,4,5,6,7,8,9];
+var result = arr.map(pow);  //map()传入的是函数对象本身
+console.log(result);       //结果:[1,4,9,16,25,36,49,64,81];
function pow(x){  //定义一个平方函数
+    return x*x;
+}
+
+var arr=[1,2,3,4,5,6,7,8,9];
+var result = arr.map(pow);  //map()传入的是函数对象本身
+console.log(result);       //结果:[1,4,9,16,25,36,49,64,81];
用给定函数创建新字符串
js
const mapString = (str, fn) =>
+  str
+    .split('')
+    .map((c, i) => fn(c, i, str))
+    .join('');
+mapString('lorem ipsum', c => c.toUpperCase()); // 'LOREM IPSUM'
const mapString = (str, fn) =>
+  str
+    .split('')
+    .map((c, i) => fn(c, i, str))
+    .join('');
+mapString('lorem ipsum', c => c.toUpperCase()); // 'LOREM IPSUM'
把二维数组变字符串
js
const arr = [[1, 2], [3, 4]];
+const str = arr.map(row => row.join(',')).join(';');
+console.log(str); // "1,2;3,4"
const arr = [[1, 2], [3, 4]];
+const str = arr.map(row => row.join(',')).join(';');
+console.log(str); // "1,2;3,4"
数字序列转为数组,删除符号
js
const digitize = n => [...\`\${Math.abs(n)}\`].map(i => parseInt(i));
+digitize(123); // [1, 2, 3]
+digitize(-123); // [1, 2, 3]
const digitize = n => [...\`\${Math.abs(n)}\`].map(i => parseInt(i));
+digitize(123); // [1, 2, 3]
+digitize(-123); // [1, 2, 3]
拿到所有图片的图片名称并以数组形式返回
js
const getImages = (el, includeDuplicates = false) => {
+  const images = [...el.getElementsByTagName('img')]
+  const srcList = images.map(img =>
+    img.getAttribute('src')
+  );
+  return includeDuplicates ? srcList : [...new Set(srcList)];
+};
+
+getImages(document, true); 
+// ['image1.jpg', 'image2.png', 'image1.png', '...']
+getImages(document, false);
+// ['image1.jpg', 'image2.png', '...'] 名字去重
const getImages = (el, includeDuplicates = false) => {
+  const images = [...el.getElementsByTagName('img')]
+  const srcList = images.map(img =>
+    img.getAttribute('src')
+  );
+  return includeDuplicates ? srcList : [...new Set(srcList)];
+};
+
+getImages(document, true); 
+// ['image1.jpg', 'image2.png', 'image1.png', '...']
+getImages(document, false);
+// ['image1.jpg', 'image2.png', '...'] 名字去重
vue中循环注册组件
js
Vue.component('ele',{
+		render:function(createElement){
+			return createElement('div',
+			    Array.apply(null,{ length:5 }).map(() => createElement(Child))
+			);
+		}
+	});
Vue.component('ele',{
+		render:function(createElement){
+			return createElement('div',
+			    Array.apply(null,{ length:5 }).map(() => createElement(Child))
+			);
+		}
+	});

高阶函数之 reduce

定义

原始数组不发生改变

对于空数组是不会执行回调函数的

语法

js
arr.reduce(callback , [initialValue])
+//callback (执行数组中每个值的函数,包含四个参数)
+//initialValue (作为第一次调用 callback 的第一个参数。)
+//如果没有提供initialValue,从索引1的地方开始执行callback方法,跳过第一个索引。
+//如果提供initialValue,从索引0开始
arr.reduce(callback , [initialValue])
+//callback (执行数组中每个值的函数,包含四个参数)
+//initialValue (作为第一次调用 callback 的第一个参数。)
+//如果没有提供initialValue,从索引1的地方开始执行callback方法,跳过第一个索引。
+//如果提供initialValue,从索引0开始
js
//执行数组中每个值的callback 函数,包含四个参数
+const sum = arr.reduce(function(previousValue, currentValue, index, array) {
+   return previousValue + currentValue;
+}0)
//执行数组中每个值的callback 函数,包含四个参数
+const sum = arr.reduce(function(previousValue, currentValue, index, array) {
+   return previousValue + currentValue;
+}0)

TIP

1、previousValue :上一次调用回调返回的值,或者是提供的初始值(initialValue)

2、currentValue :数组中当前被处理的元素

3、index :当前元素在数组中的索引

4、array :调用 reduce 函数 的数组

用法

数组求和
js
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
+sum(1, 2, 3, 4); // 10
+sum(...[1, 2, 3, 4]); // 10
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
+sum(1, 2, 3, 4); // 10
+sum(...[1, 2, 3, 4]); // 10
数组去重
js
let arr = [1,2,3,4,4,1]
+let newArr = arr.reduce((pre,cur)=> pre.includes(cur) ? pre : [...pre,cur],[])
+console.log(newArr);// [1, 2, 3, 4]
let arr = [1,2,3,4,4,1]
+let newArr = arr.reduce((pre,cur)=> pre.includes(cur) ? pre : [...pre,cur],[])
+console.log(newArr);// [1, 2, 3, 4]
计算两个或多个数字的平均值
js
const average = (...nums) =>
+  nums.reduce((acc, val) => acc + val, 0) / nums.length;
+average(...[1, 2, 3]); // 2
+average(1, 2, 3); // 2
const average = (...nums) =>
+  nums.reduce((acc, val) => acc + val, 0) / nums.length;
+average(...[1, 2, 3]); // 2
+average(1, 2, 3); // 2
将多维数组转化为一维
js
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
+const convertArr = (arr) => arr.reduce((pre,cur) => Array.isArray(cur) ? [...pre,...convertArr(cur)] : [...pre,cur],[])
+console.log(convertArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
+const convertArr = (arr) => arr.reduce((pre,cur) => Array.isArray(cur) ? [...pre,...convertArr(cur)] : [...pre,cur],[])
+console.log(convertArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
对象里的属性求和
js
var result = [
+    {
+        subject: 'math',
+        score: 10
+    },
+    {
+        subject: 'chinese',
+        score: 20
+    },
+    {
+        subject: 'english',
+        score: 30
+    }
+];
+
+var sum = result.reduce((prev, cur) => cur.score + prev, 0);
+console.log(sum) //60
var result = [
+    {
+        subject: 'math',
+        score: 10
+    },
+    {
+        subject: 'chinese',
+        score: 20
+    },
+    {
+        subject: 'english',
+        score: 30
+    }
+];
+
+var sum = result.reduce((prev, cur) => cur.score + prev, 0);
+console.log(sum) //60
统计数组中每个元素出现的次数
js
arr11 = [111, 22, 111, 234, 999, 999, 111]
+let arr1 = arr11.reduce((pre, item) => {
+    pre[item] = pre[item] ? pre[item] + 1 : 1
+    return pre
+}, {})
+//{ '22': 1, '111': 3, '234': 1, '999': 2 }
arr11 = [111, 22, 111, 234, 999, 999, 111]
+let arr1 = arr11.reduce((pre, item) => {
+    pre[item] = pre[item] ? pre[item] + 1 : 1
+    return pre
+}, {})
+//{ '22': 1, '111': 3, '234': 1, '999': 2 }
js
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
+
+let nameNum = names.reduce((pre,cur)=>{
+  if(cur in pre){
+    pre[cur]++
+  }else{
+    pre[cur] = 1 
+  }
+  return pre
+},{})
+console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
+
+let nameNum = names.reduce((pre,cur)=>{
+  if(cur in pre){
+    pre[cur]++
+  }else{
+    pre[cur] = 1 
+  }
+  return pre
+},{})
+console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}

高阶函数之 sort

定义

sort() 方法用原地算法对数组的元素进行排序,并返回数组,

该排序方法会在原数组上直接进行排序,并不会生成一个排好序的新数组

排序算法现在是稳定的。默认排序顺序是根据字符串 Unicode 码点。

语法

js
arr.sort(sortby)
+//sort() 在没有参数时,返回的结果是按升序来排列的
+
+//sortby	可选。规定排序顺序。必须是函数。
arr.sort(sortby)
+//sort() 在没有参数时,返回的结果是按升序来排列的
+
+//sortby	可选。规定排序顺序。必须是函数。

TIP

function(a, b)(return a- b)

  • 如果指明了参数:compare (a, b) ,(a, b 是两个要比较的元素,a 在 b 前面)那么数组会按照该函数的返回值排序
  • 如果 compare (a, b) 返回值 < 0 ,a 会被排列到 b 之前,即参数 a, b 的顺序保存原样;
  • 如果 compare (a, b) 返回值 = 0 ,a 和 b 的相对位置不变。(ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守)
  • 如果 compare (a, b) 返回值 > 0 ,b 会被排列到 a 之前。即交换参数 a, b 的顺序

用法

js
let sortby= function (a, b) {
+    return a - b;
+}
+let koala=[10, 20, 1, 2].sort(sortby)
+
+console.log(koala);
+// [1 , 2 , 10 , 20]
let sortby= function (a, b) {
+    return a - b;
+}
+let koala=[10, 20, 1, 2].sort(sortby)
+
+console.log(koala);
+// [1 , 2 , 10 , 20]
js
var arr = [10, 20, 1, 2];
+    arr.sort(function (x, y) {
+        if (x < y) {
+            return -1;
+        }
+        if (x > y) {
+            return 1;
+        }
+        return 0;
+    });
+console.log(arr); // [1, 2, 10, 20]
var arr = [10, 20, 1, 2];
+    arr.sort(function (x, y) {
+        if (x < y) {
+            return -1;
+        }
+        if (x > y) {
+            return 1;
+        }
+        return 0;
+    });
+console.log(arr); // [1, 2, 10, 20]

自定义高阶函数

字符串数组每项长度、并转换为整数数组

语法

  • 创建了一个高阶函数 mapForEach ,它接受一个数组和一个回调函数 fn。
  • 它循环遍历传入的数组,并在每次迭代时在 newArray.push 方法调用回调函数 fn 。
  • 回调函数 fn 接收数组的当前元素并返回该元素的长度,该元素存储在 newArray 中。
  • for 循环完成后,newArray 被返回并赋值给 lenArray。

用法

js
const strArray=['JavaScript','PHP','JAVA','C','Python'];
+function mapForEach(arr,fn){
+    const newArray = [];
+    for(let i = 0; i < arr.length;i++){
+        newArray.push(fn(arr[i]));
+    }
+    return newArray;
+}
+const lenArray = mapForEach(strArray,(str) =>  str.length);
+
+console.log(lenArray);//[10,3,4,1,6]
const strArray=['JavaScript','PHP','JAVA','C','Python'];
+function mapForEach(arr,fn){
+    const newArray = [];
+    for(let i = 0; i < arr.length;i++){
+        newArray.push(fn(arr[i]));
+    }
+    return newArray;
+}
+const lenArray = mapForEach(strArray,(str) =>  str.length);
+
+console.log(lenArray);//[10,3,4,1,6]
`,71),e=[o];function c(r,t,y,A,D,B){return a(),n("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.lean.js" "b/assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.lean.js" new file mode 100644 index 00000000..5f9052ca --- /dev/null +++ "b/assets/FrontEnd_JavaScript_\351\253\230\351\230\266\345\207\275\346\225\260.md.f3e81d0b.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/JavaScript/高阶函数.md","filePath":"FrontEnd/JavaScript/高阶函数.md"}'),p={name:"FrontEnd/JavaScript/高阶函数.md"},o=l("",71),e=[o];function c(r,t,y,A,D,B){return a(),n("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.js" "b/assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.js" new file mode 100644 index 00000000..8093fa74 --- /dev/null +++ "b/assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.js" @@ -0,0 +1,147 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"自动部署","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Shell/自动部署脚本.md","filePath":"FrontEnd/Shell/自动部署脚本.md"}'),l={name:"FrontEnd/Shell/自动部署脚本.md"},o=p(`

自动部署

脚本

sh
#!/usr/bin/env sh
+
+set -e
+
+npm run docs:build
+
+cd docs/.vitepress/dist
+
+git init 
+
+git add -A
+
+git commit -m '🎉deploy gh-pages🎉'
+
+git push -f git@github.com:fxzer/zerdocs.git master:gh-pages
+
+cd ..
+
+rm -rf  dist
+
+cd -
#!/usr/bin/env sh
+
+set -e
+
+npm run docs:build
+
+cd docs/.vitepress/dist
+
+git init 
+
+git add -A
+
+git commit -m '🎉deploy gh-pages🎉'
+
+git push -f git@github.com:fxzer/zerdocs.git master:gh-pages
+
+cd ..
+
+rm -rf  dist
+
+cd -

Action

主要流程

检查代码(Checkout) ===> 启动node环境(Setup Node) ===> 构建静态文件(Build) ===> 把静态文件push到gh-pages,触发gh-pages自带的workflow部署(Push To GitHub Pages)===> 把仓库同步到Gitee(Sync to Gitee) ===> 触发Gitee Pages服务部署(Build Gitee Pages)

yml

+name: Deploy GitHub Pages And Sync to Gitee
+
+# 触发条件:在 push 到 master 分支后
+on:
+  push:
+    branches:
+      - master
+# 任务
+jobs:
+  build-and-deploy:
+    runs-on: ubuntu-latest #部署运行环境搭建
+    steps:
+      - name: Checkout 🛎️
+        uses: actions/checkout@main
+        with:
+          persist-credentials: false
+          fetch-depth: 0 #github代码拉取深度
+      - name: Setup Node  🎬
+        uses: actions/setup-node@main
+        with:
+          node-version: "lts/*"
+      - name: Build 🔧 
+        run: |
+          yarn
+          yarn run build
+          ls -lrth
+      - name: 📲 Push To GitHub Pages
+        uses: ftnext/action-push-ghpages@v1.0.0
+        with:
+          build_dir: dist
+          github_token: \${{ secrets.DEPLOY_TOKEN }}
+      - name: 🔁 Sync to Gitee #同步到Gitee
+        uses: wearerequired/git-mirror-action@master
+        env:
+          # 注意在此项目的 Settings->Actions-> Secrets 配置 GITEE_RSA_PRIVATE_KEY
+          SSH_PRIVATE_KEY: \${{ secrets.GITEE_RSA_PRIVATE_KEY }}
+        with:
+          # 注意替换为你的 GitHub 源仓库地址
+          source-repo: 'git@github.com:fxzer/zerdocs.git'
+          # 注意替换为你的 Gitee 目标仓库地址
+          destination-repo: 'git@gitee.com:fxzer/zerdocs.git'
+      - name: ✅ Build Gitee Pages #触发Gitee自动部署
+        uses: yanglbme/gitee-pages-action@master
+        with:
+          # 注意替换为你的 Gitee 用户名
+          gitee-username: fxzer
+          # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
+          gitee-password: \${{ secrets.GITEE_PASSWORD }}
+          # 注意替换为你的 Gitee 仓库 
+          # 坑点:https://gitee.com/fxzer/zerdocs -->则填:fxzer/zerdocs,注意仓库名和路径名不一致问题
+          gitee-repo: fxzer/zerdocs 
+          # 要部署的分支
+          branch: gh-pages

+name: Deploy GitHub Pages And Sync to Gitee
+
+# 触发条件:在 push 到 master 分支后
+on:
+  push:
+    branches:
+      - master
+# 任务
+jobs:
+  build-and-deploy:
+    runs-on: ubuntu-latest #部署运行环境搭建
+    steps:
+      - name: Checkout 🛎️
+        uses: actions/checkout@main
+        with:
+          persist-credentials: false
+          fetch-depth: 0 #github代码拉取深度
+      - name: Setup Node  🎬
+        uses: actions/setup-node@main
+        with:
+          node-version: "lts/*"
+      - name: Build 🔧 
+        run: |
+          yarn
+          yarn run build
+          ls -lrth
+      - name: 📲 Push To GitHub Pages
+        uses: ftnext/action-push-ghpages@v1.0.0
+        with:
+          build_dir: dist
+          github_token: \${{ secrets.DEPLOY_TOKEN }}
+      - name: 🔁 Sync to Gitee #同步到Gitee
+        uses: wearerequired/git-mirror-action@master
+        env:
+          # 注意在此项目的 Settings->Actions-> Secrets 配置 GITEE_RSA_PRIVATE_KEY
+          SSH_PRIVATE_KEY: \${{ secrets.GITEE_RSA_PRIVATE_KEY }}
+        with:
+          # 注意替换为你的 GitHub 源仓库地址
+          source-repo: 'git@github.com:fxzer/zerdocs.git'
+          # 注意替换为你的 Gitee 目标仓库地址
+          destination-repo: 'git@gitee.com:fxzer/zerdocs.git'
+      - name: ✅ Build Gitee Pages #触发Gitee自动部署
+        uses: yanglbme/gitee-pages-action@master
+        with:
+          # 注意替换为你的 Gitee 用户名
+          gitee-username: fxzer
+          # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
+          gitee-password: \${{ secrets.GITEE_PASSWORD }}
+          # 注意替换为你的 Gitee 仓库 
+          # 坑点:https://gitee.com/fxzer/zerdocs -->则填:fxzer/zerdocs,注意仓库名和路径名不一致问题
+          gitee-repo: fxzer/zerdocs 
+          # 要部署的分支
+          branch: gh-pages
`,6),e=[o];function c(t,r,y,A,i,D){return n(),a("div",null,e)}const C=s(l,[["render",c]]);export{B as __pageData,C as default}; diff --git "a/assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.lean.js" "b/assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.lean.js" new file mode 100644 index 00000000..96a543b8 --- /dev/null +++ "b/assets/FrontEnd_Shell_\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md.7ce896dd.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"自动部署","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/Shell/自动部署脚本.md","filePath":"FrontEnd/Shell/自动部署脚本.md"}'),l={name:"FrontEnd/Shell/自动部署脚本.md"},o=p("",6),e=[o];function c(t,r,y,A,i,D){return n(),a("div",null,e)}const C=s(l,[["render",c]]);export{B as __pageData,C as default}; diff --git "a/assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.js" "b/assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.js" new file mode 100644 index 00000000..5815cce7 --- /dev/null +++ "b/assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.js" @@ -0,0 +1,987 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/TypeScript/初学笔记.md","filePath":"FrontEnd/TypeScript/初学笔记.md"}'),p={name:"FrontEnd/TypeScript/初学笔记.md"},o=l(`

基础语法

一、基础类型

JS类型

js
boolean
+number
+string
+array
+object	//对象: {}、 function(){}
+null
+undefined	//默认情况下null和undefined是所有类型的子类型。可以赋值给其他类型
boolean
+number
+string
+array
+object	//对象: {}、 function(){}
+null
+undefined	//默认情况下null和undefined是所有类型的子类型。可以赋值给其他类型

object 类型常见用法

typescript
//1.严格要求
+let b :{name: string ,age: number}
+b = { name:'zhangsan ',age :18}
//1.严格要求
+let b :{name: string ,age: number}
+b = { name:'zhangsan ',age :18}
typescript
//2.可选
+let b :{name: string ,age?: number}
+b = { name:'zhangsna '}
//2.可选
+let b :{name: string ,age?: number}
+b = { name:'zhangsna '}
typescript
//3.多个可选
+let b :{name: string ,[porname:string]:string}
+b = { name:'zhangsna ',address:'上海',gender:''}
//3.多个可选
+let b :{name: string ,[porname:string]:string}
+b = { name:'zhangsna ',address:'上海',gender:''}
typescript
//4.箭头函数设置函数结构
+let d: (c:number,d:number)=>number
+d = function(n1,n2){
+    return n1+n2
+}
//4.箭头函数设置函数结构
+let d: (c:number,d:number)=>number
+d = function(n1,n2){
+    return n1+n2
+}

数组

typescript
let arr: string[] 	//字符串数组 arr = ['zhansan','lisi']
+let arr1:Array<number>	//数值数组 arr1 = [1,2,3,4,5]
let arr: string[] 	//字符串数组 arr = ['zhansan','lisi']
+let arr1:Array<number>	//数值数组 arr1 = [1,2,3,4,5]

元组

typescript
let h: [string ,number]
+h = ['hello', 123]
let h: [string ,number]
+h = ['hello', 123]

枚举

typescript
enum Color {Red = 1, Green = 2, Blue = 4}
+let c: Color = Color.Green;  //c为2
+Color[2] // Green 枚举的值得到它的名字
enum Color {Red = 1, Green = 2, Blue = 4}
+let c: Color = Color.Green;  //c为2
+Color[2] // Green 枚举的值得到它的名字

TS新增类型

typescript
字面量	  //限制类型在几个值之间(联合类型)例:let b : 'male'|'amale' 、 
+enum	//枚举类型
+tuple	//元组 [string, number];
+void	//表示没有返回值,不返回或返回undefined,和其他类型平等关系,不能直接赋值给其他类型	
+Any		//任意类型
+unknown //未知类型 
+never	//永远不返回结果,没有类型是never的子类型、没有类型可以赋值给never类型(除了never本身之外)
+//函数用于执行不到返回值那一步,(抛出异常或死循环)的返回值类型
字面量	  //限制类型在几个值之间(联合类型)例:let b : 'male'|'amale' 、 
+enum	//枚举类型
+tuple	//元组 [string, number];
+void	//表示没有返回值,不返回或返回undefined,和其他类型平等关系,不能直接赋值给其他类型	
+Any		//任意类型
+unknown //未知类型 
+never	//永远不返回结果,没有类型是never的子类型、没有类型可以赋值给never类型(除了never本身之外)
+//函数用于执行不到返回值那一步,(抛出异常或死循环)的返回值类型

unknownany区别

typescript
let a: any
+let b: string 
+b =  a // OK  any类型可以赋值任意类型
let a: any
+let b: string 
+b =  a // OK  any类型可以赋值任意类型
typescript
let e: unknown
+e = 'TypeScript'
+let f: string
+f = e 	//Error 未知类型不能直接赋值给其他变量(类型安全的any)
+
+//处理方式一:
+if(typeof  e === "string" ){
+	f = e
+}
+//处理方式二:类型断言
+f = e as string 
+f = <string> e
let e: unknown
+e = 'TypeScript'
+let f: string
+f = e 	//Error 未知类型不能直接赋值给其他变量(类型安全的any)
+
+//处理方式一:
+if(typeof  e === "string" ){
+	f = e
+}
+//处理方式二:类型断言
+f = e as string 
+f = <string> e

|& :表示或,&:表示且

typescript
let g: string | boolean
+g = 'sdfj'
+g = true
+
+let h :string & number
+let i: {name:string} &{age:number}
+f = {
+    name:'h hh',
+    age:18
+}
let g: string | boolean
+g = 'sdfj'
+g = true
+
+let h :string & number
+let i: {name:string} &{age:number}
+f = {
+    name:'h hh',
+    age:18
+}

二、类型声名

typescript
let name:string	 //声名string类型变量
+let age = 19	 //类型声名可省略,会自动类型推断,age推断为number
let name:string	 //声名string类型变量
+let age = 19	 //类型声名可省略,会自动类型推断,age推断为number

三、as const 断言

typescript
let a = 99 as const 	//a值只能为99,指定明确的值、类型
+let b:string = 'asfghj'
+let obj = {
+    name:b,		//值只能为string
+} as const
let a = 99 as const 	//a值只能为99,指定明确的值、类型
+let b:string = 'asfghj'
+let obj = {
+    name:b,		//值只能为string
+} as const
typescript
let x = 1024
+let y = '2048'
+
+let arr = [x,y] 	// arr[1]类型是 number|string
+let arr = [x,y] as const 	// 指定为元组,arr[1]类型只能为 number
+//同:let arr = <const>[x,y]
let x = 1024
+let y = '2048'
+
+let arr = [x,y] 	// arr[1]类型是 number|string
+let arr = [x,y] as const 	// 指定为元组,arr[1]类型只能为 number
+//同:let arr = <const>[x,y]

面对对象

一、类

typescript
class 类名 {
+    属性名: 类型;
+    
+    constructor(参数: 类型){
+        this.属性名 = 参数;
+    }
+    
+    方法名(){
+        ....
+    }
+
+}
class 类名 {
+    属性名: 类型;
+    
+    constructor(参数: 类型){
+        this.属性名 = 参数;
+    }
+    
+    方法名(){
+        ....
+    }
+
+}

栗子:

typescript
    class Person{
+        name: string;
+        age: number;
+    
+        constructor(name: string, age: number){
+            this.name = name;
+            this.age = age;
+        }
+    
+        sayHello(){
+            console.log(\`大家好,我是\${this.name}\`);
+        }
+    }
    class Person{
+        name: string;
+        age: number;
+    
+        constructor(name: string, age: number){
+            this.name = name;
+            this.age = age;
+        }
+    
+        sayHello(){
+            console.log(\`大家好,我是\${this.name}\`);
+        }
+    }

构造函数

注1:在TS中只能有一个构造器方法!

typescript
class Person{
+    name: string;
+    age: number
+
+    constructor(name: string, age: number) {
+        this.name = name;
+        this.age = age;
+    }
+}
class Person{
+    name: string;
+    age: number
+
+    constructor(name: string, age: number) {
+        this.name = name;
+        this.age = age;
+    }
+}

注2:子类继承父类时,必须调用父类的构造方法(如果子类中也定义了构造方法)!

typescript
class A {
+    protected num: number;
+    constructor(num: number) {
+        this.num = num;
+    }
+}
+
+class X extends A {
+    protected name: string;
+    constructor(num: number, name: string) {
+        super(num);
+        this.name = name;
+    }
+}
class A {
+    protected num: number;
+    constructor(num: number) {
+        this.num = num;
+    }
+}
+
+class X extends A {
+    protected name: string;
+    constructor(num: number, name: string) {
+        super(num);
+        this.name = name;
+    }
+}

二、封装

  • 静态属性(static):

    • 声明为static的属性或方法不再属于实例,而是属于类的属性;
  • 只读属性(readonly):

    • 如果在声明属性时添加一个readonly,则属性便成了只读属性无法修改
  • TS中属性具有三种修饰符:

    • public(默认值),可以在类、子类和对象中修改
    • protected ,可以在类、子类中修改
    • private ,可以在类中修改
public
typescript
class Person{
+    public name: string; // 写或什么都不写都是public
+    public age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以在类中修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(\`大家好,我是\${this.name}\`);
+    }
+}
+
+class Employee extends Person{
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 可以通过对象修改
class Person{
+    public name: string; // 写或什么都不写都是public
+    public age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以在类中修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(\`大家好,我是\${this.name}\`);
+    }
+}
+
+class Employee extends Person{
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 可以通过对象修改
protected
typescript
class Person{
+    protected name: string;
+    protected age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(\`大家好,我是\${this.name}\`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改
class Person{
+    protected name: string;
+    protected age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(\`大家好,我是\${this.name}\`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中可以修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改
private
typescript
class Person{
+    private name: string;
+    private age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(\`大家好,我是\${this.name}\`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中不能修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改
class Person{
+    private name: string;
+    private age: number;
+
+    constructor(name: string, age: number){
+        this.name = name; // 可以修改
+        this.age = age;
+    }
+
+    sayHello(){
+        console.log(\`大家好,我是\${this.name}\`);
+    }
+}
+
+class Employee extends Person{
+
+    constructor(name: string, age: number){
+        super(name, age);
+        this.name = name; //子类中不能修改
+    }
+}
+
+const p = new Person('孙悟空', 18);
+p.name = '猪八戒';// 不能修改

三、属性存取器

对于一些不希望被任意修改的属性,可以将其设置为private

直接将其设置为private将导致无法再通过对象修改其中的属性

我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器

读取属性的方法叫做setter方法,设置属性的方法叫做getter方法

示例
typescript
class Person{
+    private _name: string;
+
+    constructor(name: string){
+        this._name = name;
+    }
+
+    get name(){
+        return this._name;
+    }
+
+    set name(name: string){
+        this._name = name;
+    }
+
+}
+
+const p1 = new Person('孙悟空');
+// 实际通过调用getter方法读取name属性
+console.log(p1.name);
+// 实际通过调用setter方法修改name属性 
+p1.name = '猪八戒';
class Person{
+    private _name: string;
+
+    constructor(name: string){
+        this._name = name;
+    }
+
+    get name(){
+        return this._name;
+    }
+
+    set name(name: string){
+        this._name = name;
+    }
+
+}
+
+const p1 = new Person('孙悟空');
+// 实际通过调用getter方法读取name属性
+console.log(p1.name);
+// 实际通过调用setter方法修改name属性 
+p1.name = '猪八戒';

静态属性

静态属性(方法),也称为类属性。使用静态属性无需创建实例,通过类即可直接使用

静态属性(方法)使用static开头

typescript
class Tools{
+    static PI = 3.1415926;
+    
+    static sum(num1: number, num2: number){
+        return num1 + num2
+    }
+}
+
+console.log(Tools.PI);
+console.log(Tools.sum(123, 456));
class Tools{
+    static PI = 3.1415926;
+    
+    static sum(num1: number, num2: number){
+        return num1 + num2
+    }
+}
+
+console.log(Tools.PI);
+console.log(Tools.sum(123, 456));

四、继承

通过继承可以将其他类中的属性和方法引入到当前类中,通过继承可以在不修改类的情况下完成对类的扩展

typescript
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(\`\${this.name}在汪汪叫!\`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(\`\${this.name}在汪汪叫!\`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();

重写

发生继承时,如果子类中的方法会替换掉父类中的同名方法,这就称为方法的重写

typescript
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+
+    run(){
+        console.log(\`父类中的run方法!\`);
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(\`\${this.name}在汪汪叫!\`);
+    }
+
+    run(){
+        console.log(\`子类中的run方法,会重写父类中的run方法!\`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();
class Animal{
+    name: string;
+    age: number;
+
+    constructor(name: string, age: number){
+        this.name = name;
+        this.age = age;
+    }
+
+    run(){
+        console.log(\`父类中的run方法!\`);
+    }
+}
+
+class Dog extends Animal{
+
+    bark(){
+        console.log(\`\${this.name}在汪汪叫!\`);
+    }
+
+    run(){
+        console.log(\`子类中的run方法,会重写父类中的run方法!\`);
+    }
+}
+
+const dog = new Dog('旺财', 4);
+dog.bark();

五、抽象类(abstract class)

抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例,用于抽取类的共同特点

使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现;

typescript
abstract class Animal{
+  abstract run(): void;
+  bark(){
+      console.log('动物在叫~');
+  }
+}
+
+class Dog extends Animals{
+  run(){
+      console.log('狗在跑~');
+  }
+}
abstract class Animal{
+  abstract run(): void;
+  bark(){
+      console.log('动物在叫~');
+  }
+}
+
+class Dog extends Animals{
+  run(){
+      console.log('狗在跑~');
+  }
+}

六、接口

typescript
//用于类型检查
+interface Person {
+    firstName: string;
+     lastName: string;
+     address?: string;	//可选属性
+ readonly age: number;	//只读属性
+}
+
+function greeter(person: Person) {
+    return "Hello, " + person.firstName + " " + person.lastName;
+}
//用于类型检查
+interface Person {
+    firstName: string;
+     lastName: string;
+     address?: string;	//可选属性
+ readonly age: number;	//只读属性
+}
+
+function greeter(person: Person) {
+    return "Hello, " + person.firstName + " " + person.lastName;
+}

基本配置

一、TS编译配置

但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json

tsconfig.json详细配置
js
{
+/* 
+    tsconfig.json 是ts编译器的配置文件,ts编译器可以更具它的信息来对代码进行编译
+    "include" 用来表示指定哪些ts文件需要被编译
+        路径:
+            *表示任意文件,
+            **表示任意目录
+    "exclude" 用来表示不需要被编译的文件目录
+            默认值:{"node_modules", "bower_components", "jspm_packages"}
+*/
+    "include": [
+        "./src/**/*"
+    ],
+    
+    // "exclude": [
+    //     "./src/hello/**/*"
+    // ]
+     /*
+        被继承的配置文件
+        例如:"extends": "。/configs/base",
+      */
+  //  "extends": "",
+      /*
+        指定被编译文件的列表,只有需要编译的文件少时才会用到
+      */
+    //  "files": [],
+
+    //compilerOptions 编译器的选项 
+    "compilerOptions": {
+        
+        //target 用来指定ts被编译为ES的版本
+        //'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'.
+        "target": "ES2015",
+
+        //module 指定要使用的模块化的规范
+        //'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'
+        "module": "es2015",
+        
+        //lib 用来指定项目所用的库
+       /* 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 
+       'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 
+          'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include',
+          'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 
+         'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 
+         'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', */
+
+
+        //outDir 用来指定编译后文件所在的目录
+        "outDir": "./dist",
+
+        //outFile 将代码合并为一个文件
+        // "outFile": "./dist/app.js",
+
+        // 是否对js文件进行编译,默认是false
+        "allowJs": true,
+
+        // 是否检查js代码是否符合语法规范,默认值是false
+        "checkJs": true,
+
+        // 是否移除注释
+        "removeComments": true,
+
+        // 不生成编译后的文件
+        "noEmit": false,
+
+        // 当有错误时不生成编译文件
+        "noEmitOnError": true,
+
+        // 所有严格检查的总开关
+        "strict": true,
+
+        // 用来设置编译后的文件是否使用严格模式,默认是false
+        // 在ES6中的模块化会自动使用严格模式,而无需在文件开头添加\`'use strict'\`
+        "alwaysStrict": true,
+
+        // 不允许隐式的any类型
+        "noImplicitAny": true,
+
+        // 不允许不明确类型的this
+        "noImplicitThis": true,
+
+        // 严格检查空值
+        "strictNullChecks": true
+
+
+    }
+}
{
+/* 
+    tsconfig.json 是ts编译器的配置文件,ts编译器可以更具它的信息来对代码进行编译
+    "include" 用来表示指定哪些ts文件需要被编译
+        路径:
+            *表示任意文件,
+            **表示任意目录
+    "exclude" 用来表示不需要被编译的文件目录
+            默认值:{"node_modules", "bower_components", "jspm_packages"}
+*/
+    "include": [
+        "./src/**/*"
+    ],
+    
+    // "exclude": [
+    //     "./src/hello/**/*"
+    // ]
+     /*
+        被继承的配置文件
+        例如:"extends": "。/configs/base",
+      */
+  //  "extends": "",
+      /*
+        指定被编译文件的列表,只有需要编译的文件少时才会用到
+      */
+    //  "files": [],
+
+    //compilerOptions 编译器的选项 
+    "compilerOptions": {
+        
+        //target 用来指定ts被编译为ES的版本
+        //'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'.
+        "target": "ES2015",
+
+        //module 指定要使用的模块化的规范
+        //'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'
+        "module": "es2015",
+        
+        //lib 用来指定项目所用的库
+       /* 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 
+       'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 
+          'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include',
+          'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 
+         'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 
+         'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', */
+
+
+        //outDir 用来指定编译后文件所在的目录
+        "outDir": "./dist",
+
+        //outFile 将代码合并为一个文件
+        // "outFile": "./dist/app.js",
+
+        // 是否对js文件进行编译,默认是false
+        "allowJs": true,
+
+        // 是否检查js代码是否符合语法规范,默认值是false
+        "checkJs": true,
+
+        // 是否移除注释
+        "removeComments": true,
+
+        // 不生成编译后的文件
+        "noEmit": false,
+
+        // 当有错误时不生成编译文件
+        "noEmitOnError": true,
+
+        // 所有严格检查的总开关
+        "strict": true,
+
+        // 用来设置编译后的文件是否使用严格模式,默认是false
+        // 在ES6中的模块化会自动使用严格模式,而无需在文件开头添加\`'use strict'\`
+        "alwaysStrict": true,
+
+        // 不允许隐式的any类型
+        "noImplicitAny": true,
+
+        // 不允许不明确类型的this
+        "noImplicitThis": true,
+
+        // 严格检查空值
+        "strictNullChecks": true
+
+
+    }
+}

二、webpack整合

步骤如下:

1. 初始化项目

进入项目根目录,执行命令 npm init -y,创建package.json文件

2. 下载构建工具

bash
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin

3. 配置webpack

webpack.config.js详细配置
js
// 引入一个包
+const path = require('path');
+// 引入html插件
+const HTMLWebpackPlugin = require('html-webpack-plugin');
+//引入clean插件
+const { CleanWebpackPlugin } = require('clean-webpack-plugin')
+
+// npm init -y 初始化 创建package.json文件
+// npm i -D webpack webpack-cli typescript ts-loader  安装四个依赖
+// 编写webpack配置文件
+// 编写tsconfig.json文件
+// 修改package.json中加上build命令
+// npm i -D html-webpack-plugin //自动生成html
+// npm i -D webpack-dev-server //自动响应浏览器更新
+// npm i -D clean-webpack-plugin //清楚dist目录旧文件
+
+//webpack 中所有的配置信息都应该写在module.exports中
+module.exports = {
+
+    // 指定入口文件
+    entry: "./src/index.ts",
+
+    // 指定打包文件所在目录
+    output: {
+        //指定打包文件的目录
+        path: path.resolve(__dirname, 'dist'),
+        //打包后文件的名字
+        filename: "bundle.js",
+        //告诉webpack不使用箭头函数
+        environment: {
+            arrowFunction: false
+        }
+
+    },
+    //指定webpack打包时要使用的模块
+    module: {
+        // 指定要loader加载的规则
+        rules: [
+            {
+                // test指定的时规则生效的文件
+                test: /\\.ts$/,//以ts结尾的文件
+                // 要使用的loader
+                use: [
+                    // 配置babel
+                    {
+                        //指定加载器
+                        loader: "babel-loader",
+                        // 设置babel
+                        options: {
+                            //设置预定义的环境
+                            presets: [
+                                [
+                                    //指定环境的插件
+                                    "@babel/preset-env",
+                                    // 配置信息
+                                    {
+                                        // 要兼容的目标浏览器及版本
+                                        targets: {
+                                            "chrome": "58",
+                                            "ie": "11"
+                                        },
+                                        //指定corejs的版本
+                                        "corejs": "3",
+                                        //使用corejs的方式 "usage"  表示按需加载
+                                        "useBuiltIns": "usage" 
+                                    }
+
+                                ]
+                            ]
+                        }
+                    },
+                    // 'babel-loader',
+                    'ts-loader'
+                ],
+                // 要排除的文件
+                exclude: /node-modules/
+            }
+        ]
+    },
+
+    //配置Webpack 插件
+    plugins: [
+        new CleanWebpackPlugin(),
+        new HTMLWebpackPlugin({
+            // title: "这是一个自定义的title"、
+            template: "./src/index.html" 
+        }),
+    ],
+
+    // 用来设置引用模块,可以将这些文件识别为模块
+    resolve: {
+        extensions: ['.ts', '.js']
+    }
+}
// 引入一个包
+const path = require('path');
+// 引入html插件
+const HTMLWebpackPlugin = require('html-webpack-plugin');
+//引入clean插件
+const { CleanWebpackPlugin } = require('clean-webpack-plugin')
+
+// npm init -y 初始化 创建package.json文件
+// npm i -D webpack webpack-cli typescript ts-loader  安装四个依赖
+// 编写webpack配置文件
+// 编写tsconfig.json文件
+// 修改package.json中加上build命令
+// npm i -D html-webpack-plugin //自动生成html
+// npm i -D webpack-dev-server //自动响应浏览器更新
+// npm i -D clean-webpack-plugin //清楚dist目录旧文件
+
+//webpack 中所有的配置信息都应该写在module.exports中
+module.exports = {
+
+    // 指定入口文件
+    entry: "./src/index.ts",
+
+    // 指定打包文件所在目录
+    output: {
+        //指定打包文件的目录
+        path: path.resolve(__dirname, 'dist'),
+        //打包后文件的名字
+        filename: "bundle.js",
+        //告诉webpack不使用箭头函数
+        environment: {
+            arrowFunction: false
+        }
+
+    },
+    //指定webpack打包时要使用的模块
+    module: {
+        // 指定要loader加载的规则
+        rules: [
+            {
+                // test指定的时规则生效的文件
+                test: /\\.ts$/,//以ts结尾的文件
+                // 要使用的loader
+                use: [
+                    // 配置babel
+                    {
+                        //指定加载器
+                        loader: "babel-loader",
+                        // 设置babel
+                        options: {
+                            //设置预定义的环境
+                            presets: [
+                                [
+                                    //指定环境的插件
+                                    "@babel/preset-env",
+                                    // 配置信息
+                                    {
+                                        // 要兼容的目标浏览器及版本
+                                        targets: {
+                                            "chrome": "58",
+                                            "ie": "11"
+                                        },
+                                        //指定corejs的版本
+                                        "corejs": "3",
+                                        //使用corejs的方式 "usage"  表示按需加载
+                                        "useBuiltIns": "usage" 
+                                    }
+
+                                ]
+                            ]
+                        }
+                    },
+                    // 'babel-loader',
+                    'ts-loader'
+                ],
+                // 要排除的文件
+                exclude: /node-modules/
+            }
+        ]
+    },
+
+    //配置Webpack 插件
+    plugins: [
+        new CleanWebpackPlugin(),
+        new HTMLWebpackPlugin({
+            // title: "这是一个自定义的title"、
+            template: "./src/index.html" 
+        }),
+    ],
+
+    // 用来设置引用模块,可以将这些文件识别为模块
+    resolve: {
+        extensions: ['.ts', '.js']
+    }
+}

4.配置TS编译选项

json
{
+   "compilerOptions": {
+       "target": "ES2015",
+       "module": "ES2015",
+       "strict": true
+   }
+}
{
+   "compilerOptions": {
+       "target": "ES2015",
+       "module": "ES2015",
+       "strict": true
+   }
+}

5 .修改package.json配置

typescript
{
+   ...
+   "scripts": {
+       "test": "echo \\"Error: no test specified\\" && exit 1",
+       "build": "webpack",
+       "start": "webpack serve --open chrome.exe" //使用chrome启动
+   },
+   ...
+}
{
+   ...
+   "scripts": {
+       "test": "echo \\"Error: no test specified\\" && exit 1",
+       "build": "webpack",
+       "start": "webpack serve --open chrome.exe" //使用chrome启动
+   },
+   ...
+}

6.项目使用

在src下创建ts文件,并在并命令行执行npm run build对代码进行编译;

或者执行npm start来启动开发服务器;

7.Babel

Babel作用

虽然TS在编译时也支持代码转换,但是只支持简单的代码转换;

对于例如:Promise等ES6特性,TS无法直接转换,这时还要用到babel来做转换;

7.1 安装依赖包:

npm i -D @babel/core @babel/preset-env babel-loader core-js

共安装了4个包,分别是:

  • @babel/core:babel的核心工具
  • @babel/preset-env:babel的预定义环境
  • @babel-loader:babel在webpack中的加载器
  • core-js:core-js用来使老版本的浏览器支持新版ES语法

7.2 修改webpack.config.js配置文件

js
...
+module: {
+    rules: [
+        {
+            test: /\\.ts$/,
+            use: [
+                {
+                    loader: "babel-loader",
+                    options:{
+                        presets: [
+                            [
+                                "@babel/preset-env",
+                                {	//支持的目标版本
+                                    "targets":{
+                                        "chrome": "58", 
+                                        "ie": "11"
+                                    },
+                                    //corejs版本
+                                    "corejs":"3",
+                                    "useBuiltIns": "usage"
+                                }
+                            ]
+                        ]
+                    }
+                },
+                {
+                    loader: "ts-loader",
+
+                }
+            ],
+            exclude: /node_modules/
+        }
+    ]
+}
+...
...
+module: {
+    rules: [
+        {
+            test: /\\.ts$/,
+            use: [
+                {
+                    loader: "babel-loader",
+                    options:{
+                        presets: [
+                            [
+                                "@babel/preset-env",
+                                {	//支持的目标版本
+                                    "targets":{
+                                        "chrome": "58", 
+                                        "ie": "11"
+                                    },
+                                    //corejs版本
+                                    "corejs":"3",
+                                    "useBuiltIns": "usage"
+                                }
+                            ]
+                        ]
+                    }
+                },
+                {
+                    loader: "ts-loader",
+
+                }
+            ],
+            exclude: /node_modules/
+        }
+    ]
+}
+...
`,86),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.lean.js" "b/assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.lean.js" new file mode 100644 index 00000000..90c9c489 --- /dev/null +++ "b/assets/FrontEnd_TypeScript_\345\210\235\345\255\246\347\254\224\350\256\260.md.a7be054a.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/TypeScript/初学笔记.md","filePath":"FrontEnd/TypeScript/初学笔记.md"}'),p={name:"FrontEnd/TypeScript/初学笔记.md"},o=l("",86),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.js" "b/assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.js" new file mode 100644 index 00000000..abe0d48a --- /dev/null +++ "b/assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.js" @@ -0,0 +1,53 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/TypeScript/进阶使用技巧.md","filePath":"FrontEnd/TypeScript/进阶使用技巧.md"}'),o={name:"FrontEnd/TypeScript/进阶使用技巧.md"},l=p(`

松散类型自动推推导

ts
//1.
+type Size = "sm" | "xs"
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs"
+}
+
+// 2.
+type Size = "sm" | "xs" | string
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,但模版中使用失去类型提示
+}
+
+//3.
+type Size = "sm" | "xs" | Omit<string,"sm" | "xs">
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
+
+//4.封装为 type
+type Size = LooseAutoComplete<"sm" | "xs">
+type LooseAutoComplete<T extends string> = T | Omit<string, T>
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
//1.
+type Size = "sm" | "xs"
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs"
+}
+
+// 2.
+type Size = "sm" | "xs" | string
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,但模版中使用失去类型提示
+}
+
+//3.
+type Size = "sm" | "xs" | Omit<string,"sm" | "xs">
+
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
+
+//4.封装为 type
+type Size = LooseAutoComplete<"sm" | "xs">
+type LooseAutoComplete<T extends string> = T | Omit<string, T>
+interface IconProps {
+  size:Size // size 可以推导为 "sm" | "xs" | string ,保留模版类型提示
+}
`,2),t=[l];function e(c,r,y,A,D,i){return n(),a("div",null,t)}const C=s(o,[["render",e]]);export{B as __pageData,C as default}; diff --git "a/assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.lean.js" "b/assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.lean.js" new file mode 100644 index 00000000..564983c8 --- /dev/null +++ "b/assets/FrontEnd_TypeScript_\350\277\233\351\230\266\344\275\277\347\224\250\346\212\200\345\267\247.md.21fda5ca.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/TypeScript/进阶使用技巧.md","filePath":"FrontEnd/TypeScript/进阶使用技巧.md"}'),o={name:"FrontEnd/TypeScript/进阶使用技巧.md"},l=p("",2),t=[l];function e(c,r,y,A,D,i){return n(),a("div",null,t)}const C=s(o,[["render",e]]);export{B as __pageData,C as default}; diff --git "a/assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.js" "b/assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.js" new file mode 100644 index 00000000..01dca3b2 --- /dev/null +++ "b/assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.js" @@ -0,0 +1,265 @@ +import{_ as s,o as n,c as a,Q as o}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"Typescript 配置文件(tsconfig.json)解析","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/TypeScript/配置文件详解.md","filePath":"FrontEnd/TypeScript/配置文件详解.md"}'),l={name:"FrontEnd/TypeScript/配置文件详解.md"},p=o(`

Typescript 配置文件(tsconfig.json)解析

TypeScript带来的类型系统以及强大的IDE支持,让前端开发也变得严谨而流畅。但TypeScript不是原生的Javascript代码,需要进行编译才能转换为Javascript代码。

tsconfig.json是编译TypeScript的配置文件,对书写TypeScript代码十分重要。因为有些选项如果你没配置,则需要严格按照TypeScript的规则来书写,对初期使用TypeScript的同学而言,稍不留神就会书写出不符合规则的代码,从而导致编译报错,打击自信心。其实早期可以通过关闭一些规则设置,从而更愉快的从js转为ts开发。笔者根据项目实战经历来解释一些常用的编译选项,文末也会附上笔者整理的所有tsconfig.json选项的解释。

1. experimentalDecorators

是否启用实验性的ES装饰器。boolean类型,默认值:false。官方解释(opens new window)

TypeScript和ES6中引入了Class的概念,同时在stage 2 proposal (opens new window)提出了Java等服务器端语言早就有的装饰器模式。通过引入装饰器模式,能极大简化书写代码,把一些通用逻辑封装到装饰器中。很多库都有用到该特性,比如vue-class-component 及 vuex-class等库。当你使用这些库时,必须开启experimentalDecorators

ts
function f() {
+    console.log("f(): evaluated");
+    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
+        console.log("f(): called");
+    }
+}
+
+class C {
+    @f()
+    method() {}
+}
function f() {
+    console.log("f(): evaluated");
+    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
+        console.log("f(): called");
+    }
+}
+
+class C {
+    @f()
+    method() {}
+}

启用 vuex-class同时需要设置strictFunctionTypes选项为false

2. strictPropertyInitialization

是否类的非undefined属性已经在构造函数里初始化。 boolean类型,默认值:false

直白点,就是所有的属性值,都需要赋有初始值。建议把strictPropertyInitialization设置为false,这样就不需要定义一个变量就必须赋有初始值。对使用vuex-class库的同学,建议请把这个值设为false,绝对能省很多事。

ts
export default class Home extend Vue{
+    jobId: string // 如果开启strictPropertyInitialization,则这里会报错,因为没有赋值默认值
+
+    method1() :void {
+        console.log(this.jobId)
+    }
+}
export default class Home extend Vue{
+    jobId: string // 如果开启strictPropertyInitialization,则这里会报错,因为没有赋值默认值
+
+    method1() :void {
+        console.log(this.jobId)
+    }
+}

如果设置该选项为true,需要同时启用--strictNullChecks或启用--strict

3. noImplicitAny

有隐含的 any类型时是否报错。boolean值,默认值:false

ts是有默认推导的,同时还有any类型,所以不是每个变量或参数定义需要明确告知类型是什么。如果开启该值,当有隐含any类型时,会报错。建议初次上手TypeScript,把该选项设置为false。

ts
// 当开启noImplicitAny时,需要隐含当any需要明确指出
+arr.find(item => item.name === name) // error
+arr.find((item: any) => item.name === name) // ok
// 当开启noImplicitAny时,需要隐含当any需要明确指出
+arr.find(item => item.name === name) // error
+arr.find((item: any) => item.name === name) // ok

4. target

指定编译的ECMAScript目标版本。枚举值:"ES3", "ES5", "ES6"/ "ES2015", "ES2016", "ES2017","ESNext"。默认值: “ES3”

TypeScript是ES6的超集,所以你可以使用ES6来编写ts代码(通常我们也的确这么做)。然而,当编译ts代码时,可以把ts转为ES5或更早的js代码。所以需要选择一个编译的目标版本。vue-cli3的typescript模板,设置为“ESNext”,因为现代大部分应用项目都会使用Webpack(Parcel也很棒)进行打包,Webpack会把你的代码转换成在所有浏览器中可运行的代码。

target: "ESNext" 是指tc39最新的ES proposed features(opens new window)

5. module

指定生成哪个模块系统代码。枚举值:"None", "CommonJS", "AMD", "System", "UMD", "ES6", "ES2015","ESNext"。默认值根据--target选项不同而不同,当target设置为ES6时,默认module为“ES6”,否则为“commonjs”

通常使用ES6的模块来写ts代码,然而2016年1月以前,基本上没有浏览器原生支持ES6的模块系统,所以需要转换为不同的模块系统,如:CommonJS、AMD、SystemJS等,而module选项就是指定编译使用对应的模块系统。

6. lib

编译过程中需要引入的库文件的列表。string[]类型,可选的值有很多,常用的有ES5,ES6,ESNext,DOM,DOM.Iterable、WebWorker、ScriptHost等。该值默认值是根据--target选项不同而不同。当target为ES5时,默认值为['DOM ', 'ES5', 'ScriptHost'];当target为ES6时,默认值为['DOM', 'ES6', 'DOM.Iterable', 'ScriptHost']

为了在ts代码中使用ES6中的类,比如Array.form、Set、Reflect等,需要设置lib选项,在编译过程中把这些标准库引入。这样在编译过程中,如果遇到属于这些标准库的class或api时,ts编译器不会报错。

7. moduleResolution

决定如何处理模块。string类型,“node”或者“classic”,默认值:“classic”。官方解释(opens new window)

说直白点,也就是遇到import { AAA } from './aaa'该如何去找对应文件模块解析。对于工程项目,笔者建议大家使用node(vue-cli3 ts模板默认设置为node策略),因为这个更符合平时我们的书写习惯以及认知(平时都是webpack打包,webpack又基于node之上)。

text
// 在源文件/root/src/A.ts中import { b } from "./moduleB"
+// 两种解析方式查找文件方式不同
+
+// classic模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.d.ts
+
+// node模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.tsx
+3. /root/src/moduleB.d.ts
+4. /root/src/moduleB/package.json (if it specifies a "types" property)
+5. /root/src/moduleB/index.ts
+6. /root/src/moduleB/index.tsx
+7. /root/src/moduleB/index.d.ts
// 在源文件/root/src/A.ts中import { b } from "./moduleB"
+// 两种解析方式查找文件方式不同
+
+// classic模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.d.ts
+
+// node模块解析方式
+1. /root/src/moduleB.ts
+2. /root/src/moduleB.tsx
+3. /root/src/moduleB.d.ts
+4. /root/src/moduleB/package.json (if it specifies a "types" property)
+5. /root/src/moduleB/index.ts
+6. /root/src/moduleB/index.tsx
+7. /root/src/moduleB/index.d.ts

8. paths

模块名或路径映射的列表。Object值

这是一个非常有用的选项,比如我们经常使用'@/util/help'来代替'./src/util/help',省的每次在不同层级文件import模块时,都纠结于是'./'还是'../'。该选项告诉编译器遇到匹配的值时,去映射的路径下加载模块。

ts
{
+    "baseUrl": ".", // 注意:baseUrl不可少
+    "paths": {
+      // 映射列表
+      "@/*": [
+        "src/*"
+      ],
+      "moduleA": [
+        "src/libs/moduleA"
+      ]
+    }
+}
+
+// in ts code
+import Setting from '@/components/Setting.vue' // 模块实际位置: src/components/Setting.vue
+import TestModule from 'moduleA/index.js' // 模块实际位置: src/libs/moduleA/index.js
{
+    "baseUrl": ".", // 注意:baseUrl不可少
+    "paths": {
+      // 映射列表
+      "@/*": [
+        "src/*"
+      ],
+      "moduleA": [
+        "src/libs/moduleA"
+      ]
+    }
+}
+
+// in ts code
+import Setting from '@/components/Setting.vue' // 模块实际位置: src/components/Setting.vue
+import TestModule from 'moduleA/index.js' // 模块实际位置: src/libs/moduleA/index.js

9. strictNullChecks

是否启用严格的 null检查模式。boolean值,默认值:false

未处理的null和undefined经常会导致BUG的产生,所以TypeScript包含了strictNullChecks选项来帮助我们减少对这种情况的担忧。当启用了strictNullChecks,null和undefined获得了它们自己各自的类型null和undefined。开启该模式有助于发现并处理可能为undefined的赋值。如果是正式项目,笔者建议开启该选项;如果只是练手TypeScirpt,可以关闭该选项,不然所有可能为null/undefined的赋值,都需要写联合类型。

ts
// 未开启strictNullChecks,number类型包含了null和undefined类型
+let foo: number = 123;
+foo = null; // Okay
+foo = undefined; // Okay
+
+// 开启strictNullChecks
+let foo: string[] | undefined = arr.find(key => key === 'test')
+// foo.push('1') // error - 'foo' is possibly 'undefined'
+foo && foo.push('1') // okay
// 未开启strictNullChecks,number类型包含了null和undefined类型
+let foo: number = 123;
+foo = null; // Okay
+foo = undefined; // Okay
+
+// 开启strictNullChecks
+let foo: string[] | undefined = arr.find(key => key === 'test')
+// foo.push('1') // error - 'foo' is possibly 'undefined'
+foo && foo.push('1') // okay

注意:启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks, --strictFunctionTypes和--strictPropertyInitialization

10. noUnusedLocals

有未使用的变量时,是否抛出错误。boolean值,默认值: false

顾名思义,当发现变量定义但没有使用时,编译不报错。eslint的rule中也有该条,建议正式项目将该选项开启,设置为true,使得代码干净整洁。

11. noUnusedParameters

有未使用的参数时,是否抛出错误。boolean值,默认值: false

建议正式项目开启该选项,设置为true,理由同上。

12. allowJs

是否允许编译javascript文件。boolean值,默认值:false

如果设置为true,js后缀的文件也会被typescript进行编译。

13. typeRoots和types

默认所有可见的"@types"包会在编译过程中被包含进来。如果指定了typeRoots,只有typeRoots下面的包才会被包含进来。如果指定了types,只有被列出来的npm包才会被包含进来。详细内容可看此处(opens new window)

可以指定"types": []来禁用自动引入@types包

14. files、include和exclude

编译文件包含哪些文件以及排除哪些文件

未设置include时,编译器默认包含当前目录和子目录下所有的TypeScript文件(.ts, .d.ts 和 .tsx)。如果allowJs被设置成true,JS文件(.js和.jsx)也被包含进来。exclude排除那些不需要编译的文件或文件夹。

ts
{
+    "compilerOptions": {},
+    "include": [
+        "src/**/*"
+    ],
+    "exclude": [
+        "node_modules",
+        "**/*.spec.ts"
+    ]
+}
{
+    "compilerOptions": {},
+    "include": [
+        "src/**/*"
+    ],
+    "exclude": [
+        "node_modules",
+        "**/*.spec.ts"
+    ]
+}

tsconfig.json全解析

json
{
+  "compilerOptions": {
+    /* 基本选项 */
+    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'("ESNext"表示最新的ES语法,包括还处在stage X阶段)
+    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
+    "lib": [],                             // 指定要包含在编译中的库文件
+    "allowJs": true,                       // 允许编译 javascript 文件
+    "checkJs": true,                       // 报告 javascript 文件中的错误
+    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
+    "declaration": true,                   // 生成相应的 '.d.ts' 文件
+    "sourceMap": true,                     // 生成相应的 '.map' 文件
+    "outFile": "./",                       // 将输出文件合并为一个文件
+    "outDir": "./",                        // 指定输出目录
+    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
+    "removeComments": true,                // 删除编译后的所有的注释
+    "noEmit": true,                        // 不生成输出文件
+    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
+    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
+
+    /* 严格的类型检查选项 */
+    "strict": true,                        // 启用所有严格类型检查选项
+    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
+    "strictNullChecks": true,              // 启用严格的 null 检查
+    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
+    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
+
+    /* 额外的检查 */
+    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
+    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
+    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
+    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
+
+    /* 模块解析选项 */
+    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)。默认是classic
+    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
+    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
+    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
+    "typeRoots": [],                       // 包含类型声明的文件列表
+    "types": [],                           // 需要包含的类型声明文件名列表
+    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。
+
+    /* Source Map Options */
+    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
+    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
+    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
+    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
+
+    /* 其他选项 */
+    "experimentalDecorators": true,        // 启用装饰器
+    "emitDecoratorMetadata": true,         // 为装饰器提供元数据的支持
+    "strictFunctionTypes": false           // 禁用函数参数双向协变检查。
+  },
+  /* 指定编译文件或排除指定编译文件 */
+  "include": [
+      "src/**/*"
+  ],
+  "exclude": [
+      "node_modules",
+      "**/*.spec.ts"
+  ],
+  "files": [
+    "core.ts",
+    "sys.ts"
+  ],
+  // 从另一个配置文件里继承配置
+  "extends": "./config/base",
+  // 让IDE在保存文件的时候根据tsconfig.json重新生成文件
+  "compileOnSave": true // 支持这个特性需要Visual Studio 2015, TypeScript1.8.4以上并且安装atom-typescript插件
+}
{
+  "compilerOptions": {
+    /* 基本选项 */
+    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'("ESNext"表示最新的ES语法,包括还处在stage X阶段)
+    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
+    "lib": [],                             // 指定要包含在编译中的库文件
+    "allowJs": true,                       // 允许编译 javascript 文件
+    "checkJs": true,                       // 报告 javascript 文件中的错误
+    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
+    "declaration": true,                   // 生成相应的 '.d.ts' 文件
+    "sourceMap": true,                     // 生成相应的 '.map' 文件
+    "outFile": "./",                       // 将输出文件合并为一个文件
+    "outDir": "./",                        // 指定输出目录
+    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
+    "removeComments": true,                // 删除编译后的所有的注释
+    "noEmit": true,                        // 不生成输出文件
+    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
+    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
+
+    /* 严格的类型检查选项 */
+    "strict": true,                        // 启用所有严格类型检查选项
+    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
+    "strictNullChecks": true,              // 启用严格的 null 检查
+    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
+    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
+
+    /* 额外的检查 */
+    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
+    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
+    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
+    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
+
+    /* 模块解析选项 */
+    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)。默认是classic
+    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
+    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
+    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
+    "typeRoots": [],                       // 包含类型声明的文件列表
+    "types": [],                           // 需要包含的类型声明文件名列表
+    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。
+
+    /* Source Map Options */
+    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
+    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
+    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
+    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
+
+    /* 其他选项 */
+    "experimentalDecorators": true,        // 启用装饰器
+    "emitDecoratorMetadata": true,         // 为装饰器提供元数据的支持
+    "strictFunctionTypes": false           // 禁用函数参数双向协变检查。
+  },
+  /* 指定编译文件或排除指定编译文件 */
+  "include": [
+      "src/**/*"
+  ],
+  "exclude": [
+      "node_modules",
+      "**/*.spec.ts"
+  ],
+  "files": [
+    "core.ts",
+    "sys.ts"
+  ],
+  // 从另一个配置文件里继承配置
+  "extends": "./config/base",
+  // 让IDE在保存文件的时候根据tsconfig.json重新生成文件
+  "compileOnSave": true // 支持这个特性需要Visual Studio 2015, TypeScript1.8.4以上并且安装atom-typescript插件
+}
`,58),e=[p];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const E=s(l,[["render",t]]);export{B as __pageData,E as default}; diff --git "a/assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.lean.js" "b/assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.lean.js" new file mode 100644 index 00000000..b8f2b59f --- /dev/null +++ "b/assets/FrontEnd_TypeScript_\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md.7a55465d.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as o}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"Typescript 配置文件(tsconfig.json)解析","description":"","frontmatter":{},"headers":[],"relativePath":"FrontEnd/TypeScript/配置文件详解.md","filePath":"FrontEnd/TypeScript/配置文件详解.md"}'),l={name:"FrontEnd/TypeScript/配置文件详解.md"},p=o("",58),e=[p];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const E=s(l,[["render",t]]);export{B as __pageData,E as default}; diff --git a/assets/GoodTool_index.md.2cde5d0e.js b/assets/GoodTool_index.md.2cde5d0e.js new file mode 100644 index 00000000..5875ec2d --- /dev/null +++ b/assets/GoodTool_index.md.2cde5d0e.js @@ -0,0 +1 @@ +import{_ as m,o as n,c as s,p as x,m as y,k as e,d as f,h as k,g as j,a4 as h,a9 as g,H as w,t as b,F as _,D as v,l as T,b as $,a as I}from"./chunks/framework.c53372a0.js";const z={},r=t=>(x("data-v-4fdc7ada"),t=t(),y(),t),S={class:"loader"},C=r(()=>e("div",null,null,-1)),D=r(()=>e("div",null,null,-1)),G=r(()=>e("div",null,null,-1)),L=r(()=>e("div",null,null,-1)),N=[C,D,G,L];function P(t,i){return n(),s("div",S,N)}const V=m(z,[["render",P],["__scopeId","data-v-4fdc7ada"]]),O=["href"],B=["alt","src"],F={class:"tool-name"},A=f({__name:"ToolItem",props:{tool:{type:Object,required:!0}},setup(t){const{tool:i}=t,a=k(!1),u=j(()=>{let{icon:o,iconType:c,url:p}=i;return o||p+"favicon."+(c||"ico")}),d=o=>{o.target.src="https://zerdocs.oss-cn-shanghai.aliyuncs.com/202302062047848.svg"},l=o=>{a.value=!0,o.target.onerror=null,o.target.onload=null};return(o,c)=>{const p=V;return n(),s("a",{class:"tool-item",href:t.tool.url,target:"blank"},[h(w(p,{class:"tool-icon"},null,512),[[g,!a.value]]),h(e("img",{class:"tool-icon",alt:t.tool.name,src:u.value,onload:l,onError:d},null,40,B),[[g,a.value]]),e("p",F,b(t.tool.name),1)],8,O)}}});const E=m(A,[["__scopeId","data-v-2525f4e1"]]),H={在线编程工具:[{name:"Lightly",iconType:"svg",url:"https://lightly.teamcode.com/"},{name:"码上掘金",icon:"https://juejin.cn/favicon.ico",url:"https://code.juejin.cn"},{name:"Glitch",url:"https://glitch.com/"},{name:"CodePen",url:"https://codepen.io/"},{name:"CodeSandbox",url:"https://codesandbox.io/"},{name:"Stackblitz",url:"https://stackblitz.com/",icon:"https://c.staticblitz.com/assets/favicon-editor-675989317f34707a17fe9d649da3609d70f6f8abc9546445389238ddd570a1d4.png"}],前端组件库:[{name:"Element-UI",url:"https://element.eleme.cn/"},{name:"Ant Design",icon:"https://ng.ant.design/assets/img/logo.svg",url:"https://ant.design/index-cn/"},{name:"Arco Design",icon:"https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico",url:"https://arco.design/vue/docs/start"},{name:"Vant",icon:"https://fastly.jsdelivr.net/npm/@vant/assets/logo.png",url:"https://vant-contrib.gitee.io/vant/#/zh-CN"},{name:"Motion Vueuse",url:"https://motion.vueuse.org/"}],作图工具:[{name:"Figma",url:"www.figma.com/",icon:"https://static.figma.com/app/icon/1/favicon.ico"},{name:"ProcessOn",url:"https://www.processon.com/"},{name:"知犀思维导图",url:"https://www.zhixi.com/"},{name:"ioDraw",icon:"https://www.iodraw.com/static/img/common/iodraw.svg",url:"https://www.iodraw.com"},{name:"jsoncrack",url:"https://jsoncrack.com/"},{name:"JSON Viewer",icon:"https://fxzer.gitee.io/json-viewer/jvlogo.svg",url:"https://fxzer.gitee.io/json-viewer/"}],调色板:[{name:"FlatuiColors",icon:"https://flatuicolors.com/static/favicon.ico",url:"https://flatuicolors.com/"},{name:"Color Hunt",icon:"https://www.colorhunt.co/img/colorhunt-favicon.svg?2",url:"https://www.colorhunt.co/"},{name:"Arco Palette",icon:"https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico",url:"https://arco.design/palette/list"},{name:"ioDraw",icon:"https://webkul.github.io/coolhue/images/coolhue-logo.png",url:"https://webkul.github.io/coolhue/"},{name:"中国传统色",url:"http://zhongguose.com/"},{name:"GradientHunt",icon:"https://gradienthunt.com/img/gradienthunt.png",url:"https://gradienthunt.com/"},{name:"uigradients",icon:"https://uigradients.com/static/images/favicon-32x32.png",url:"https://uigradients.com/"},{name:"Coolors",icon:"https://coolors.co/assets/img/favicon.png",url:"https://coolors.co/"},{name:"MyColor",icon:"https://mycolor.space/img/color-space-logo.png",url:"https://mycolor.space/"}]},W={class:"tool-wrap"},J={class:"tool-group-title"},M={class:"tool-group"},q=f({__name:"ToolWrap",setup(t){return(i,a)=>{const u=E;return n(),s("div",W,[(n(!0),s(_,null,v(T(H),(d,l)=>(n(),s(_,{key:l},[e("div",J,b(l),1),e("div",M,[(n(!0),s(_,null,v(d,(o,c)=>(n(),$(u,{key:c,tool:o},null,8,["tool"]))),128))])],64))),128))])}}});const U=m(q,[["__scopeId","data-v-a04e210c"]]),K=e("h1",{id:"实用工具集锦",tabindex:"-1"},[I("实用工具集锦 "),e("a",{class:"header-anchor",href:"#实用工具集锦","aria-label":'Permalink to "实用工具集锦"'},"​")],-1),X=JSON.parse('{"title":"实用工具集锦","description":"","frontmatter":{},"headers":[],"relativePath":"GoodTool/index.md","filePath":"GoodTool/index.md"}'),Q={name:"GoodTool/index.md"},Y=Object.assign(Q,{setup(t){return(i,a)=>(n(),s("div",null,[K,w(U)]))}});export{X as __pageData,Y as default}; diff --git a/assets/GoodTool_index.md.2cde5d0e.lean.js b/assets/GoodTool_index.md.2cde5d0e.lean.js new file mode 100644 index 00000000..5875ec2d --- /dev/null +++ b/assets/GoodTool_index.md.2cde5d0e.lean.js @@ -0,0 +1 @@ +import{_ as m,o as n,c as s,p as x,m as y,k as e,d as f,h as k,g as j,a4 as h,a9 as g,H as w,t as b,F as _,D as v,l as T,b as $,a as I}from"./chunks/framework.c53372a0.js";const z={},r=t=>(x("data-v-4fdc7ada"),t=t(),y(),t),S={class:"loader"},C=r(()=>e("div",null,null,-1)),D=r(()=>e("div",null,null,-1)),G=r(()=>e("div",null,null,-1)),L=r(()=>e("div",null,null,-1)),N=[C,D,G,L];function P(t,i){return n(),s("div",S,N)}const V=m(z,[["render",P],["__scopeId","data-v-4fdc7ada"]]),O=["href"],B=["alt","src"],F={class:"tool-name"},A=f({__name:"ToolItem",props:{tool:{type:Object,required:!0}},setup(t){const{tool:i}=t,a=k(!1),u=j(()=>{let{icon:o,iconType:c,url:p}=i;return o||p+"favicon."+(c||"ico")}),d=o=>{o.target.src="https://zerdocs.oss-cn-shanghai.aliyuncs.com/202302062047848.svg"},l=o=>{a.value=!0,o.target.onerror=null,o.target.onload=null};return(o,c)=>{const p=V;return n(),s("a",{class:"tool-item",href:t.tool.url,target:"blank"},[h(w(p,{class:"tool-icon"},null,512),[[g,!a.value]]),h(e("img",{class:"tool-icon",alt:t.tool.name,src:u.value,onload:l,onError:d},null,40,B),[[g,a.value]]),e("p",F,b(t.tool.name),1)],8,O)}}});const E=m(A,[["__scopeId","data-v-2525f4e1"]]),H={在线编程工具:[{name:"Lightly",iconType:"svg",url:"https://lightly.teamcode.com/"},{name:"码上掘金",icon:"https://juejin.cn/favicon.ico",url:"https://code.juejin.cn"},{name:"Glitch",url:"https://glitch.com/"},{name:"CodePen",url:"https://codepen.io/"},{name:"CodeSandbox",url:"https://codesandbox.io/"},{name:"Stackblitz",url:"https://stackblitz.com/",icon:"https://c.staticblitz.com/assets/favicon-editor-675989317f34707a17fe9d649da3609d70f6f8abc9546445389238ddd570a1d4.png"}],前端组件库:[{name:"Element-UI",url:"https://element.eleme.cn/"},{name:"Ant Design",icon:"https://ng.ant.design/assets/img/logo.svg",url:"https://ant.design/index-cn/"},{name:"Arco Design",icon:"https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico",url:"https://arco.design/vue/docs/start"},{name:"Vant",icon:"https://fastly.jsdelivr.net/npm/@vant/assets/logo.png",url:"https://vant-contrib.gitee.io/vant/#/zh-CN"},{name:"Motion Vueuse",url:"https://motion.vueuse.org/"}],作图工具:[{name:"Figma",url:"www.figma.com/",icon:"https://static.figma.com/app/icon/1/favicon.ico"},{name:"ProcessOn",url:"https://www.processon.com/"},{name:"知犀思维导图",url:"https://www.zhixi.com/"},{name:"ioDraw",icon:"https://www.iodraw.com/static/img/common/iodraw.svg",url:"https://www.iodraw.com"},{name:"jsoncrack",url:"https://jsoncrack.com/"},{name:"JSON Viewer",icon:"https://fxzer.gitee.io/json-viewer/jvlogo.svg",url:"https://fxzer.gitee.io/json-viewer/"}],调色板:[{name:"FlatuiColors",icon:"https://flatuicolors.com/static/favicon.ico",url:"https://flatuicolors.com/"},{name:"Color Hunt",icon:"https://www.colorhunt.co/img/colorhunt-favicon.svg?2",url:"https://www.colorhunt.co/"},{name:"Arco Palette",icon:"https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico",url:"https://arco.design/palette/list"},{name:"ioDraw",icon:"https://webkul.github.io/coolhue/images/coolhue-logo.png",url:"https://webkul.github.io/coolhue/"},{name:"中国传统色",url:"http://zhongguose.com/"},{name:"GradientHunt",icon:"https://gradienthunt.com/img/gradienthunt.png",url:"https://gradienthunt.com/"},{name:"uigradients",icon:"https://uigradients.com/static/images/favicon-32x32.png",url:"https://uigradients.com/"},{name:"Coolors",icon:"https://coolors.co/assets/img/favicon.png",url:"https://coolors.co/"},{name:"MyColor",icon:"https://mycolor.space/img/color-space-logo.png",url:"https://mycolor.space/"}]},W={class:"tool-wrap"},J={class:"tool-group-title"},M={class:"tool-group"},q=f({__name:"ToolWrap",setup(t){return(i,a)=>{const u=E;return n(),s("div",W,[(n(!0),s(_,null,v(T(H),(d,l)=>(n(),s(_,{key:l},[e("div",J,b(l),1),e("div",M,[(n(!0),s(_,null,v(d,(o,c)=>(n(),$(u,{key:c,tool:o},null,8,["tool"]))),128))])],64))),128))])}}});const U=m(q,[["__scopeId","data-v-a04e210c"]]),K=e("h1",{id:"实用工具集锦",tabindex:"-1"},[I("实用工具集锦 "),e("a",{class:"header-anchor",href:"#实用工具集锦","aria-label":'Permalink to "实用工具集锦"'},"​")],-1),X=JSON.parse('{"title":"实用工具集锦","description":"","frontmatter":{},"headers":[],"relativePath":"GoodTool/index.md","filePath":"GoodTool/index.md"}'),Q={name:"GoodTool/index.md"},Y=Object.assign(Q,{setup(t){return(i,a)=>(n(),s("div",null,[K,w(U)]))}});export{X as __pageData,Y as default}; diff --git "a/assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.js" "b/assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.js" new file mode 100644 index 00000000..077735e5 --- /dev/null +++ "b/assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.js" @@ -0,0 +1 @@ +import{_ as a,o as l,c as o,Q as t}from"./chunks/framework.c53372a0.js";const _=JSON.parse('{"title":"事件循环机制","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Brower/事件循环机制.md","filePath":"Interview/Brower/事件循环机制.md"}'),i={name:"Interview/Brower/事件循环机制.md"},e=t('

事件循环机制

进程与线程

描述

进程是操作系统分配资源的基本单位,线程是操作系统调度的基本单位,线程可以看做轻量级的进程。

  1. 一个进程中至少包含一个线程,线程不能包含进程,不能单独存在,必须由进程启动和管理

  2. 多个进程间不能共享资源,都有自己私有的程序计数器(记录执行指令地址),线程可以共享同一个进程间的资源

  3. 上下文切换:进程慢,线程快(从一个切换到另一个)

  4. 操纵者不同:进程操纵者是操作系统,线程操纵者一般为程序员

image-20230223165307358

浏览器的线程与进程

浏览器是一个多进程多线程的应用程序

  1. 浏览器进程:负责浏览器界面展示、用户交互、子进程管理等;浏览器进程内部会启动多个线程处理不同的任务。
  2. 网络进程:负责加载网络资源,网络进程内部会启动多个线程来处理不同的网络任务。
  3. 渲染进程:渲染进程启动后,会启动一个渲染主进程,主进程负责执行 HTML、CSS、JS 代码。

默认每个标签页开启一个新进程,以保证标签页之间不互相影响。

渲染进程任务

  1. 解析 HTML
  2. 解析 CSS
  3. 计算 样式
  4. 页面布局
  5. 处理图层
  6. 每秒把页面渲染 60 次
  7. 执行全局 JS 代码
  8. 执行事件处理函数
  9. 执行定时器的回调函数

事件循环

2023-03-05-21-01-25

事件循环解释
  1. 在最开始的时候,渲染主线程会进入一个无限循环

  2. 每一次循环会检查消息队列中是否有任务存在。如果有,就取出第一个任务执行,执行完一个后进入下一次循环;如果没有,则进入休眠状态。

  3. 其他所有线程(包括其他进程的线程)可以随时向消息队列添加任务。新任务会加到消息队列的未尾。在添加新任务时,“如果主线程是休眠状态,则会将其唤醒以绁续循环拿取任务;如此循环往复,持续进行。

异步与事件循环理解

单线程是异步产生的原因,事件循环是异步的实现方式。

如何理解异步

Js是一门单线程的语言,这是因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。

而渲染主线程承担渲染页面、执行 JS 等诸多的任务。

如果使用同步的方式,就极有可能导致主线程产生阻塞,从而导致消息队列中的很多其他任务无法得到执行。

这样一来,一方面会导致繁忙的主线程白白的消耗时间,另一方面导致页面无法及时更新,给用户造成卡死现象。

所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时,比如计时器、网络、事件监听,主线程将任务交给其他线程去处理;

自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的未尾排队,等待主线程调度执行。

在这种异步模式下,浏览器永不阻塞,从而最大限度的保证了单线程的流畅运行。使用异步的方式,渲染主线程永不阻塞

消息队列

任务没有优先级,在消息队列中先进先出。但是 消息队列有优先级

每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不同类型的任务可以分属于不同的队列。

在一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行。

浏览器必须准备好一个微队列,微队列中的任务优先所有其他任务执行。

JS 中的计时器能做到精确计时吗

不行,因为有操作系统计时函数偏差、事件循环机制的损耗:

1.计算机硬件没有原子钟,无法做到精确计时

2.操作系统的计时函数本身就有少量偏差! 由于 JS 的计时器最终调用的是操作系统的函数,也就携带了此偏养

3.按照 W3C 的标准,浏览器实现计时器时,如果嵌套层级超过 5 层,间隔时间少于 4 毫秒,则会增加到 4 毫秒 这又带来了偏差

4. 受事件循环的影响,计时器的回调函数只能在主线程空闲时运行,因此又带来了偏差。

2023-03-05-21-56-25

',21),s=[e];function r(p,c,n,h,d,u){return l(),o("div",null,s)}const b=a(i,[["render",r]]);export{_ as __pageData,b as default}; diff --git "a/assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.lean.js" "b/assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.lean.js" new file mode 100644 index 00000000..5a58eb84 --- /dev/null +++ "b/assets/Interview_Brower_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.9f053692.lean.js" @@ -0,0 +1 @@ +import{_ as a,o as l,c as o,Q as t}from"./chunks/framework.c53372a0.js";const _=JSON.parse('{"title":"事件循环机制","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Brower/事件循环机制.md","filePath":"Interview/Brower/事件循环机制.md"}'),i={name:"Interview/Brower/事件循环机制.md"},e=t("",21),s=[e];function r(p,c,n,h,d,u){return l(),o("div",null,s)}const b=a(i,[["render",r]]);export{_ as __pageData,b as default}; diff --git "a/assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.js" "b/assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.js" new file mode 100644 index 00000000..5ab83674 --- /dev/null +++ "b/assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.js" @@ -0,0 +1 @@ +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.c53372a0.js";const b=JSON.parse('{"title":"浏览器网页请求过程","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Brower/浏览器网页请求过程.md","filePath":"Interview/Brower/浏览器网页请求过程.md"}'),l={name:"Interview/Brower/浏览器网页请求过程.md"},i=o('

浏览器网页请求过程

  1. 网络:请求资源
  2. 渲染:处理渲染

完整的 HTTP 请求过程

域名解析 ==> 与服务器建立连接 ==> 发起 HTTP 请求 ==> 服务器响应 HTTP 请求,浏览器得到 html 代码 ==> 浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片) ==> 浏览器对页面进行渲染呈现给用户

一、域名解析

  1. Chrome 浏览器 会首先搜索浏览器自身的 DNS 缓存,有且没有过期则解析到此结束。
  2. 如果浏览器自身的缓存里面没有找到对应的条目,会搜索操作系统自身的 DNS 缓存,有且没有过期则停止搜索解析到此结束

Windows 系统:ipconfig/displaydns 命令查看

  1. 如果在 Windows 系统的 DNS 缓存也没有找到,则读取 hosts 文件

hosts 位于 ‪C:\\Windows\\System32\\drivers\\etc\\hosts

  1. hosts 文件中也没有找到对应的条目,浏览器就会发起一个 DNS 的系统调用,就会向本地配置的首选 DNS 服务器发起域名解析请求

    并返回给 Windows 系统内核,内核又把结果返回给浏览器。(这是递归的请求,也就是运营商的 DNS 服务器必须得提供并返回该域名的 IP 地址)

  2. 经过以上的 4 个步骤,还没有解析成功

注:一般会进行以下几步

操作系统就会查找 NetBIOS name Cache == > WINS 服务器 ==> 客户端就要进行广播查找 ==> 客户端就读取 LMHOSTS 文件

如果还没有解析成功,那么就宣告这次解析失败,那就无法跟目标计算机进行通信。只要其中有一步可以解析成功,那就可以成功和目标计算机进行通信。

二、与服务器建立连接

  1. TCP 连接的建立

客户端的请求到达服务器,首先就是三次握手建立 TCP 连接

三次握手的目的:试探一下对方是否遵循 TCP/IP 协议,为了在不可靠的信道上建立起可靠的连接

为什么要进行第三次握手:为了防止服务器端开启一些无用的连接,增加服务器开销;

以及防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

img

三、发起 HTTP 请求

http 协议:计算机通过网络进行通信的规则,是一个基于请求与响应,无状态的,应用层的协议,常基于 TCP/IP 协议传输数据。

请求报文结构

请求报文包括四个部分:请求行,请求头,空行,请求体。

img

四、服务器端响应 HTTP 请求,浏览器得到 HTML 代码

HTTP 的响应报文也由四部分组成:响应行、响应头、空行、响应体

img

报文结构参考

五、浏览器渲染过程

2023-03-05-22-05-19

  1. 解析 html 结构,形成 Dom 树
  2. 解析 CSS,生成 cssom
  3. 将 CSSOM 和 DOM 合并形成 render 树
  4. 计算 layout 布局
  5. 将布局渲染到屏幕上

整个渲染流程分为多个阶段,分别是: HTML 解析、样式计算、布局、分层、绘制、分块、光栅化、画

一、解析 HTML

解析过程中遇到 CSS 解析 CSS,遇到 JS执行 JS。为了提高解析效率,浏览器在开始解析前,会启动一个预解析的线程,率先下载 HTML 中的外部 CSS 文件和外部的JS 文件。

如果主线程解析到 link 位置,此时外部的CSS 文件还没有下载解析好,主线程不会等待,继续解析后续的 HTML。这是因为下载和解析 css 的工作是在预解析线程中进行的。这就是csS 不会阻塞 HTML 解析的根本原因。

如果主线程解析到 script 位置,会停止解析 HTML,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML。这是因为 Js 代码的执行过程可能会修改当前的DOM 树,所以 DOM 树的生成必须暂停。这就是 JS 会阳塞 HTML 解析的根本原因。

第一步完成后,会得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、外部样式、行内样式均会包含在 CSSOM 树中。 2023-03-05-22-07-542023-03-05-22-29-15

解析成对象,提供 JS 可操作的能力

二、解析 CSS

2023-03-05-22-10-48

document.styleSheets、document.styleSheets[0].addRule('div':'border :2px solid red') 可查看、操作浏览器样式表

三、样式计算

主线程会遍历得到的DOM 树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style

在这一过程中,很多预设值会变成绝对值,比如 red 会变成 rgb;相对单位会变成绝对单位,比如 em 会变成 px

这一步完成后,会得到一棵带有样式的DOM 树

2023-03-05-22-31-23

四、布局Layout

DOM树和 Layout 不一定是一一对应的,比如head默认样式display:none,::before在 Layout 树阶段,布局完成后形成布局树。

2023-03-05-22-38-44

五、分层Layer

主线程使用复杂的策略对布局树进行分层。

六、绘制Paint

为每个层生成绘制指令

七、分块Tiling

分块工作交给多个线程同时进行

八、光栅化Raster

合成线程将信息交给 GPU 进程,将每个快变成位图,优先处理靠近视口的块,此过程会用到 GPU 加速,提升运算速率。

九、画Draw

合成线程计算出每个位图在屏幕上的位置,交给 GPU 进行呈现。变形(旋转,缩放,倾斜)等发生在合成线程,与渲染主线程无关,这是 transform 效率高的本质原因。

2023-03-06-21-54-14

回流reflow

2023-03-06-21-56-10

reflow 的本质就是重新计算 layout 树。

当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。

为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 ref1ow 是异步完成的。

也同样因为如此,当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息浏览器在反复权衡下,最终决定获取属性立即 ref1ow。

引起回流属性和方法:任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。

  1. 页面首次渲染
  2. 添加或者删除可见的DOM元素
  3. 元素尺寸或位置发生改变
  4. 元素字体大小变化
  5. 浏览器窗口大小发生改变
  6. 激活CSS伪类(例如::hover)
  7. 查询某些属性或调用某些方法

重绘repaint

repaint 的本质就是重新根据分层信息计算了绘制指令。

当改动了可见样式后,就需要重新计算,会引发 repaint。

由于元素的布局信息也属于可见样式,所以reflow 一定会引起 repaint。

2023-03-06-22-20-02

为什么 transform 的效率高?

因为 transform 既不会影响布局也不会影响绘制指令,它影响的只是渲染流程的最后一个「draw」 阶段由于 draw 阶段在合成线程中;

所以 transform 的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌.也不会影响 transform 的变化。

需要更新属性,只是影响元素的外观、风格,不影响布局。改变 ​color​​​,​ ​background-color​​​, ​​visibility 等属性

参考链接

六、浏览器对页面进行渲染呈现给用户,关闭连接

四次挥手

img

问题一:

为什么连接的时候是三次握手,关闭的时候却是四次握手?

为了保障数据发送完再断开连接

问题二:

为什么要等待一段时间在关闭连接?

因为客户端发送完 ack 包后中途可能丢失,此时服务端未收到 ack 包会重发 fin 包,客户端在发送 ack 包刷新等待时间,

确保服务端关闭再 关闭客户端

参考视频 1

参考视频 2

',84),r=[i];function s(p,c,h,n,d,m){return e(),t("div",null,r)}const A=a(l,[["render",s]]);export{b as __pageData,A as default}; diff --git "a/assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.lean.js" "b/assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.lean.js" new file mode 100644 index 00000000..d6b03b11 --- /dev/null +++ "b/assets/Interview_Brower_\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md.1acb73dd.lean.js" @@ -0,0 +1 @@ +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.c53372a0.js";const b=JSON.parse('{"title":"浏览器网页请求过程","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Brower/浏览器网页请求过程.md","filePath":"Interview/Brower/浏览器网页请求过程.md"}'),l={name:"Interview/Brower/浏览器网页请求过程.md"},i=o("",84),r=[i];function s(p,c,h,n,d,m){return e(),t("div",null,r)}const A=a(l,[["render",s]]);export{b as __pageData,A as default}; diff --git "a/assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.js" "b/assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.js" new file mode 100644 index 00000000..a83c9f81 --- /dev/null +++ "b/assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.js" @@ -0,0 +1 @@ +import{_ as t,o as e,c as a,Q as o}from"./chunks/framework.c53372a0.js";const q=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Brower/计算机网络.md","filePath":"Interview/Brower/计算机网络.md"}'),r={name:"Interview/Brower/计算机网络.md"},s=o('

http与https区别

http:超文本传输协议,明文传输,信息不安全。用的是80端口

https:具有安全性的ssl加密传输协议,信息安全。用的443端口

前端缓存

HTTP缓存

在服务器代码上设置

  1. 强缓存:使用Expires、Cache-Control(优先级高

判断过程: 请求再次发起 -> 浏览器根据 expires 和 cache-control 判断目标资源是否命中"强缓存" -> 若命中,直接从缓存获取资源,不再与服务器发生通讯。

  1. 协商缓存:协商缓存主要有四个头字段,它们两两组合配合使用,当命中协商缓存的时候,服务器会返回HTTP状态码304,让客户端直接 从本地缓存里面读取文件。

浏览器缓存

localStorage、sessionStorage、cookie

',11),l=[s];function h(i,n,c,p,_,d){return e(),a("div",null,l)}const m=t(r,[["render",h]]);export{q as __pageData,m as default}; diff --git "a/assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.lean.js" "b/assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.lean.js" new file mode 100644 index 00000000..78df3f6d --- /dev/null +++ "b/assets/Interview_Brower_\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md.73c84072.lean.js" @@ -0,0 +1 @@ +import{_ as t,o as e,c as a,Q as o}from"./chunks/framework.c53372a0.js";const q=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Brower/计算机网络.md","filePath":"Interview/Brower/计算机网络.md"}'),r={name:"Interview/Brower/计算机网络.md"},s=o("",11),l=[s];function h(i,n,c,p,_,d){return e(),a("div",null,l)}const m=t(r,[["render",h]]);export{q as __pageData,m as default}; diff --git "a/assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.js" "b/assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.js" new file mode 100644 index 00000000..e7938679 --- /dev/null +++ "b/assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.js" @@ -0,0 +1,155 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"CSS基础面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/CSS/基础面试题.md","filePath":"Interview/CSS/基础面试题.md"}'),p={name:"Interview/CSS/基础面试题.md"},o=l(`

CSS基础面试题

伪类与伪元素

解释

都不需要添加额外的HTML元素的情况下为文档添加样式和效果。

伪类:开头为单冒号:,伪类是选择器的一种,用于给元素某种状态(滑动、点击等)添加对应的样式,在原本元素上修改

伪元素:开头为双冒号::,用于创建一些不在文档树中的又可以通过 CSS 控制样式的虚拟元素,向元素添加额外的内容或样式。

image-20230227112239445

image-20230227112221284

:nth-child():nth-of-type()

:nth-child(n) :匹配到第 n 个兄弟

:nth-of-type(n):匹配到同类型的第 n 个兄弟元素

水平垂直居中

  1. 行内元素:text-align 与 line-height 块级元素:
  2. flex + margin:auto、grid + margin:auto
css
.parent{
+  display: flex; /* grid */
+}
+.children{
+  margin:auto; 
+}
.parent{
+  display: flex; /* grid */
+}
+.children{
+  margin:auto; 
+}
  1. flex布局
css
.parent{
+  display: flex; 
+  justify-content: center;
+  align-items:center;
+}
.parent{
+  display: flex; 
+  justify-content: center;
+  align-items:center;
+}
  1. grid布局
css
.parent{
+  display: grid; 
+  justify-content: center;
+  align-items:center;/* 网格内项目垂直居中 */
+}
+
+/* 或 */
+
+.box{
+  display: grid;
+  justify-content:center;
+  align-content: center;/* 容器内网格垂直居中 */
+}
.parent{
+  display: grid; 
+  justify-content: center;
+  align-items:center;/* 网格内项目垂直居中 */
+}
+
+/* 或 */
+
+.box{
+  display: grid;
+  justify-content:center;
+  align-content: center;/* 容器内网格垂直居中 */
+}
  1. 绝对定位 + transform
css
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 50%;
+  left:50%;
+  transform: translate(-50%,-50%);   
+}
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 50%;
+  left:50%;
+  transform: translate(-50%,-50%);   
+}
  1. 绝对定位 + margin
css
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 0;
+  left:0;
+  right:0;
+  bottom:0;
+  margin:auto;
+}
.parent{
+  position: relative;
+}
+.children{
+  position: absolute;
+  top: 0;
+  left:0;
+  right:0;
+  bottom:0;
+  margin:auto;
+}

盒模型的理解

当对一个文档进行布局(layout)的时候,浏览器的渲染引擎会根据标准,把每个元素表示为一个矩形的盒子。

盒模型从内到外由 content(内容) + padding(内边距) + border(边框) + margin(外边距) 组成。

默认为W3C 标准盒模型 content-boxbox-sizing:content-box: height = content 。

可以通过box-sizing改变其计算方式,通常改为怪异盒模型box-sizing:border-box: height = content + padding + border 。

这样能够更精确地控制元素的尺寸和定位,元素的宽度和高度可以直接指定为内容区域的尺寸,而无需考虑内边距和边框。

BFC 及其应用

所谓 BFC块格式化上下文),指的是一个独立的布局环境,BFC 内部的元素布局与外部互不影响。

  • 浮动元素(float 值不为 none)
  • 块级元素的 overflow 属性不为 visible,clip
  • 绝对定位的元素 包含 position: fixedposition: absolute
  • display: inline-blockdisplay: table-cellflex,grid

应用

  1. 解决相邻元素外边距塌陷
  2. 清除浮动解决父元素高度塌陷

CSS 选择器

!important权重最高

权重

1000:内联样式

100: id选择器

10:类、伪类、属性选择器

1:标签、伪元素选择器

0:子元素、后代、通配符、相邻选择器

多个可进行累加,相同属性后定义覆盖先定义。

2023-03-18-23-39-34

如何实现动画

  1. 用 CSS @keyframes关键帧
  2. 使用 JS 的 setIntervalrequestAnimationFrame,手动控制元素的位置和样式来实现动画效果

实现渐变背景

  1. 使用 CSS3 渐变,通过 linear-gradientradial-gradient 属性来实现, background: linear-gradient(to right, #ff00cc, #333399)

  2. 使用 SVG 渐变,通过定义一个 <linearGradient><radialGradient> 元素来实现

html
<svg width="100%" height="100%">
+   <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
+     <stop offset="0%" stop-color="#f00"/>
+     <stop offset="100%" stop-color="#00f"/>
+   </linearGradient>
+   <rect x="0" y="0" width="100%" height="100%" fill="url(#gradient)"/>
+ </svg>
<svg width="100%" height="100%">
+   <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
+     <stop offset="0%" stop-color="#f00"/>
+     <stop offset="100%" stop-color="#00f"/>
+   </linearGradient>
+   <rect x="0" y="0" width="100%" height="100%" fill="url(#gradient)"/>
+ </svg>

定位position

静态定位static:默认值,此时 top, right, bottom, leftz-index 属性无效

相对定位relative:保留原来位置进行定位,定位时相对于原来位置进行定位

绝对定位absolute:元素会被移出正常文档流,并不为元素预留空间,相对于最近的非 static 定位祖先元素的偏移,直到 body

固定定位fixed:相对于浏览器视口进行定位,当元素祖先的 transformperspectivefilterbackdrop-filter 属性非 none 时,容器由视口改为该祖先。

黏性定位sticky:相对于最近滚动祖先定位,滚动到元素top小于设定值(top:20px;)则转为固定定位。(relative+fixed)

隐藏元素的方式

image-20230221172950214

用css3实现饼图

css
.pie{
+  width: 500px;
+  height: 500px;
+  border-radius: 50%;
+  /* 画饼图 */
+  background: conic-gradient(
+    red 6deg,
+    orange 6deg 18deg,
+    yellow 18deg 45deg,
+    green 45deg 110deg,
+    blue 110deg 200deg,
+    purple 200deg
+  );
+}
.pie{
+  width: 500px;
+  height: 500px;
+  border-radius: 50%;
+  /* 画饼图 */
+  background: conic-gradient(
+    red 6deg,
+    orange 6deg 18deg,
+    yellow 18deg 45deg,
+    green 45deg 110deg,
+    blue 110deg 200deg,
+    purple 200deg
+  );
+}

margin和padding适用场景

marginPadding
需要在边框留白需要在边框留白
留白处不需要背景色时留白处需要背景色时
上下相连的元素,会相互抵消15px+20px的margin,得到20px的空白上下相连的元素,会累加15px+20px的padding,得到35px的空白

清除margin塌陷 兄弟相邻元素:overflow: hidden、flex 布局

html
 <div class="container">
+      <div class="item">1</div>
+      <!--<div class="wrap">  1.额外包一层并加上 overflow: hidden;-->
+        <div class="item">2</div>
+      <!--</div>-->
+    </div>
 <div class="container">
+      <div class="item">1</div>
+      <!--<div class="wrap">  1.额外包一层并加上 overflow: hidden;-->
+        <div class="item">2</div>
+      <!--</div>-->
+    </div>
css
.container {
+  border: 1px solid #ccc;
+  /* 2.形成 BFC: display: flex; */
+  
+}
+.wrap {
+  overflow: hidden;
+}
+.item {
+  height: 100px;
+  width: 100px;
+  margin: 10px;
+  overflow: hidden;
+  border: 1px solid #ccc;
+}
.container {
+  border: 1px solid #ccc;
+  /* 2.形成 BFC: display: flex; */
+  
+}
+.wrap {
+  overflow: hidden;
+}
+.item {
+  height: 100px;
+  width: 100px;
+  margin: 10px;
+  overflow: hidden;
+  border: 1px solid #ccc;
+}

父子相邻 margin 重叠

(1)给父元素添加透明边框

(2)给父元素添加overflow: hidden;

(3)给父元素添加position: fixed;

(4)给父元素添加display: table/flex/grid;

(5)将子元素都margin改为父元素的padding

可替换元素

在 HTML 中, 是指其内容不受文档流影响,而是由外部资源定义的元素。

这些元素的内容可以通过 CSS 样式或者 JavaScript 来修改,但是本身的标签和属性并不能直接控制其显示效果。

常见的可替换元素包括 img、input、textarea、select、video、audio

Canvas和SVG区别

Canvas和SVG都是用于创建图形的HTML5元素,但它们有着不同的工作原理和适用场景。

Canvas是一种基于位图的绘图技术,它使用JavaScript在HTML5画布中创建像素级别的图形,可以制作出非常复杂的动态效果。Canvas要求开发者掌握像素级别的操作,需要自己编写代码来实现各种绘图功能,因此相对较难掌握。

而SVG是基于矢量图形的绘图技术,它利用XML描述二维图形,并通过浏览器解析渲染出来。由于SVG是基于矢量图形的绘图技术,所以它具有无限放大和缩小不失真的优势。另外,SVG也具有更好的可访问性和SEO性能。

总的来说,如果需要制作交互式和复杂的图形应用程序,Canvas是更好的选择;而如果需要制作高质量的静态图形、图表或图标等,则SVG更适合。

矢量图形

矢量图形是由数学方程描述的二维图形,通常使用直线、曲线、多边形和文本等基本几何形状来创建。相比于位图图像(如JPEG、PNG等),矢量图形不会失真或模糊,无论放大或缩小都保持清晰度,因为它们是基于数学公式创建的,并且可以被无限放大或缩小而不会失去精度。此外,矢量图形还可以编辑和修改,使得它们在设计、制作标志、海报、传单、名片、网站等方面的应用非常广泛。

使用Base64编码的图片具有以下优点:

  1. 减少HTTP请求:将多个小图片合并为一个Base64编码字符串,可以减少浏览器与服务器之间的HTTP请求次数,提高页面加载速度。

  2. 更好的页面性能:由于Base64编码后的图片是直接嵌入在HTML或CSS中的,而不需要额外的文件下载,因此可以更快地加载页面,提高页面性能。

  3. 简单易用:使用Base64编码的图片无需考虑图片路径等问题,只需要将编码后的字符串嵌入到HTML或CSS代码中即可。

  4. 可减少服务器负载:由于使用Base64编码的图片无需额外的文件下载,减少了服务器的负载。这对于高流量网站来说非常重要。

缺点:

  1. 图片大小增大:由于Base64编码会将图片转换成文本形式,因此会使得图片的大小增加约1/3左右。

  2. 编码和解码需要计算资源:由于编码和解码都需要进行大量的计算,因此可能会影响页面加载速度。

  3. 不适合大型图片:对于较大的图片(尤其是超过几百KB的图片),使用Base64编码会导致HTML或CSS文件变得非常大,影响页面加载速度。

优化大量图片的加载方法,提高用户体验:

  1. 压缩图片:使用图片压缩工具,将图片大小进行压缩,可以减少图片文件的大小,从而加快加载速度。

  2. 使用图片CDN:将图片存储在专门的CDN(内容分发网络)服务器上,可以使得图片加载更快,同时也减轻了原始服务器的负载。

  3. 延迟加载:将页面上非关键图片设置为延迟加载,当用户滚动到页面的对应位置时再加载图片,可以减少初始加载时的负担,提高页面的加载速度和响应性。

  4. 使用矢量图形代替位图:对于一些简单的图标和装饰性元素,可以使用矢量图形代替位图。矢量图形在放大或缩小时不会失真,并且通常比位图更小。

  5. 利用浏览器缓存:将图片缓存在用户的浏览器中,可以减少重复加载同一张图片的次数,提高页面加载速度。

  6. 懒加载:懒加载可以避免在页面中加载不必要的图片,只有用户需要查看某张图片时才会被加载。这种方式可以大幅减少初始页面加载时间,提高用户体验。

  7. 合并多个小图片成一张大图:将多张小图片合并到一张大图中,通过CSS定位显示指定位置的小图片,可以减少请求次数,提高页面加载速度。

优雅降级和渐进增强

优雅降级:在编写项目时,直接针对最高级、最稳定的版本进行开发。然后在后续对低版本进行兼容。 渐进增强:在编写项目时,针对自己想个兼容的最低版本进行开发。然后在后续对高版本的新特性开发,或者更好的体验

新项目css架构设计入手方向

  1. 公共变量(主题色/主要空隙/主要字号字体等)
  2. 编译器(scss/less/postcss/stylus)
  3. 自适应方案(栅格/rem/vw/pt)
  4. 目录约定(mixin/common/theme/module/response)
  5. 私有化方案(scoped/css module/css in js)

Tailwindcss断点对应设备

Breakpoint prefixMinimum widthCSS代表设备
不写--手机
sm640px@media (min-width: 640px) { ... }大屏手机
md768px@media (min-width: 768px) { ... }768-1024代表 Ipad(Ipad Mini = 768)
lg1024px@media (min-width: 1024px) { ... }iPad Pro
xl1280px@media (min-width: 1280px) { ... }小型笔记本
2xl1536px@media (min-width: 1536px) { ... }电脑显示器
`,86),e=[o];function t(c,r,y,i,d,A){return a(),n("div",null,e)}const C=s(p,[["render",t]]);export{B as __pageData,C as default}; diff --git "a/assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.lean.js" "b/assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.lean.js" new file mode 100644 index 00000000..e1cd185d --- /dev/null +++ "b/assets/Interview_CSS_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.b72bdb12.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"CSS基础面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/CSS/基础面试题.md","filePath":"Interview/CSS/基础面试题.md"}'),p={name:"Interview/CSS/基础面试题.md"},o=l("",86),e=[o];function t(c,r,y,i,d,A){return a(),n("div",null,e)}const C=s(p,[["render",t]]);export{B as __pageData,C as default}; diff --git "a/assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.js" "b/assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.js" new file mode 100644 index 00000000..2dff97f3 --- /dev/null +++ "b/assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.js" @@ -0,0 +1,141 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/CSS/进阶面试题.md","filePath":"Interview/CSS/进阶面试题.md"}'),p={name:"Interview/CSS/进阶面试题.md"},o=l(`

实现一个元素的宽高比

css
.wrapper {
+    width: 100%;
+    height: 0;
+    padding-top: 56.25%; /* 16:9 宽高比 */
+    position: relative;
+}
+
+.content {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+}
.wrapper {
+    width: 100%;
+    height: 0;
+    padding-top: 56.25%; /* 16:9 宽高比 */
+    position: relative;
+}
+
+.content {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+}

维持正方形: 宽度发生改变时,利用伪元素撑开高度,从而保持正方形。

css
.square::after {
+  content: "";
+  display: block;
+  padding-bottom: 100%;
+}
.square::after {
+  content: "";
+  display: block;
+  padding-bottom: 100%;
+}

Sass 中@mixin 与@extend的区别

主要区别在于代码生成的方式

@mixin会直接将@mixin中的样式复制到@include处,而@extend则会生成一个新的选择器,并继承被@extend的选择器的样式。 因此,@mixin适用于将一组样式应用于多个选择器,而@extend适用于继承现有样式并生成新的选择器。

scss

+/* @extend:在现有样式加上加上新类名 */
+.button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @extend .button-style;
+}
+
+.button-secondary {
+  @extend .button-style;
+}
+
+/* @mixin:把样式复制到指定类名 */
+@mixin button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @include button-style;
+}
+
+.button-secondary {
+  @include button-style;
+}

+/* @extend:在现有样式加上加上新类名 */
+.button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @extend .button-style;
+}
+
+.button-secondary {
+  @extend .button-style;
+}
+
+/* @mixin:把样式复制到指定类名 */
+@mixin button-style {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-primary {
+  @include button-style;
+}
+
+.button-secondary {
+  @include button-style;
+}

转化结果:

css
@charset "UTF-8";
+/* @extend:在现有样式加上加上新类名 */
+.button-style, .button-secondary, .button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+/* @mixin:把样式复制到指定类名 */
+.button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-secondary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
@charset "UTF-8";
+/* @extend:在现有样式加上加上新类名 */
+.button-style, .button-secondary, .button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+/* @mixin:把样式复制到指定类名 */
+.button-primary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
+
+.button-secondary {
+  background-color: blue;
+  color: white;
+  border: none;
+  padding: 10px;
+}
`,9),e=[o];function c(t,r,y,A,i,D){return n(),a("div",null,e)}const d=s(p,[["render",c]]);export{B as __pageData,d as default}; diff --git "a/assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.lean.js" "b/assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.lean.js" new file mode 100644 index 00000000..233f08e6 --- /dev/null +++ "b/assets/Interview_CSS_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.6b9b42f1.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/CSS/进阶面试题.md","filePath":"Interview/CSS/进阶面试题.md"}'),p={name:"Interview/CSS/进阶面试题.md"},o=l("",9),e=[o];function c(t,r,y,A,i,D){return n(),a("div",null,e)}const d=s(p,[["render",c]]);export{B as __pageData,d as default}; diff --git "a/assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.js" "b/assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.js" new file mode 100644 index 00000000..b3c6c8be --- /dev/null +++ "b/assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as r}from"./chunks/framework.c53372a0.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/CSS/高级面试题.md","filePath":"Interview/CSS/高级面试题.md"}'),a={name:"Interview/CSS/高级面试题.md"};function n(o,s,_,c,i,p){return t(),r("div")}const f=e(a,[["render",n]]);export{m as __pageData,f as default}; diff --git "a/assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.lean.js" "b/assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.lean.js" new file mode 100644 index 00000000..b3c6c8be --- /dev/null +++ "b/assets/Interview_CSS_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.63a54546.lean.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as r}from"./chunks/framework.c53372a0.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/CSS/高级面试题.md","filePath":"Interview/CSS/高级面试题.md"}'),a={name:"Interview/CSS/高级面试题.md"};function n(o,s,_,c,i,p){return t(),r("div")}const f=e(a,[["render",n]]);export{m as __pageData,f as default}; diff --git "a/assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.js" "b/assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.js" new file mode 100644 index 00000000..b598203f --- /dev/null +++ "b/assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.js" @@ -0,0 +1,275 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/Promise相关.md","filePath":"Interview/JavaScript/Promise相关.md"}'),p={name:"Interview/JavaScript/Promise相关.md"},o=l(`

前端如何做到并发请求

  1. 使用AJAX及其各种高级封装的异步技术,如jQuery的$.ajax()、axios等;
  2. 使用Promise(ES6)异步编程,如使用axios.all()或者Promise.all()多个请求并发发出;
  3. 使用Web Workers技术,将任务并发分发到多个Web Worker中执行;
  4. 使用WebSocket技术,可单个持久链接上进行多次请求;
  5. 使用Stream API技术,浏览器可以同时消费多个数据流,实现多个请求的并发;
  6. 使用定时器setInterval()及setTimeout(),可定时发出多个需要并发请求;

方法一:封装队列

js
 class taskQueue {
+    constructor() {
+      this.queue = [];
+      this.result = [];
+      this.error = [];
+      this.max = 3;
+      setTimeout(() => {
+        this.run();
+      }, 0);
+    }
+    addTask(task) {
+      this.queue.push(task);
+    }
+    async run() {
+      const length = this.queue.length;
+      if (length === 0) return;
+      const min = Math.min(length, this.max);
+      for (let i = 0; i < min; i++) {
+        this.max--; //开始占用任务空间
+        const task = this.queue.shift();
+        try {
+          const res = await task();
+          console.log("[ res ]-131", res);
+          this.result.push(res);
+        } catch (err) {
+          this.error.push(err);
+        } finally {
+          this.max++; //释放占用空间
+          this.run();
+        }
+      }
+    }
+  }
+
+  //测试
+  function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const task = new taskQueue();
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  times.forEach((item) => {
+    task.addTask(createTask(item));
+  });
 class taskQueue {
+    constructor() {
+      this.queue = [];
+      this.result = [];
+      this.error = [];
+      this.max = 3;
+      setTimeout(() => {
+        this.run();
+      }, 0);
+    }
+    addTask(task) {
+      this.queue.push(task);
+    }
+    async run() {
+      const length = this.queue.length;
+      if (length === 0) return;
+      const min = Math.min(length, this.max);
+      for (let i = 0; i < min; i++) {
+        this.max--; //开始占用任务空间
+        const task = this.queue.shift();
+        try {
+          const res = await task();
+          console.log("[ res ]-131", res);
+          this.result.push(res);
+        } catch (err) {
+          this.error.push(err);
+        } finally {
+          this.max++; //释放占用空间
+          this.run();
+        }
+      }
+    }
+  }
+
+  //测试
+  function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const task = new taskQueue();
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  times.forEach((item) => {
+    task.addTask(createTask(item));
+  });

方法二:函数封装

js
// 并发请求函数
+const concurrencyRequest = (tasks, maxNum) => {
+  return new Promise((resolve) => {
+    if (tasks.length === 0) {
+      resolve([]);
+      return;
+    }
+    const results = [];
+    let index = 0; // 下一个请求的下标
+    let count = 0; // 当前请求完成的数量
+
+    // 发送请求
+    async function request() {
+      if (index === tasks.length) return;
+      const i = index; // 保存序号,使result和tasks相对应
+      index++;
+      try {
+        const resp = await tasks[i]();
+        console.log("[ resp ]-29", resp);
+        results[i] = resp;
+      } catch (err) {
+        results[i] = err;
+      } finally {
+        count++;
+        // 判断是否所有的请求都已完成
+        if (count === tasks.length) {
+          console.log("完成了");
+          resolve(results);
+        }
+        request();
+      }
+    }
+    const times = Math.min(maxNum, tasks.length);
+    for (let i = 0; i < times; i++) {
+      request();
+    }
+  });
+};
+
+//测试代码
+function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  const tasks = times.map((item) => createTask(item));
+  console.log("[ tasks ]-141", tasks);
+  concurrencyRequest(tasks, 3).then((res) => {
+    console.log("[ res ]-143", res);
+  });
// 并发请求函数
+const concurrencyRequest = (tasks, maxNum) => {
+  return new Promise((resolve) => {
+    if (tasks.length === 0) {
+      resolve([]);
+      return;
+    }
+    const results = [];
+    let index = 0; // 下一个请求的下标
+    let count = 0; // 当前请求完成的数量
+
+    // 发送请求
+    async function request() {
+      if (index === tasks.length) return;
+      const i = index; // 保存序号,使result和tasks相对应
+      index++;
+      try {
+        const resp = await tasks[i]();
+        console.log("[ resp ]-29", resp);
+        results[i] = resp;
+      } catch (err) {
+        results[i] = err;
+      } finally {
+        count++;
+        // 判断是否所有的请求都已完成
+        if (count === tasks.length) {
+          console.log("完成了");
+          resolve(results);
+        }
+        request();
+      }
+    }
+    const times = Math.min(maxNum, tasks.length);
+    for (let i = 0; i < times; i++) {
+      request();
+    }
+  });
+};
+
+//测试代码
+function createTask(delay) {
+    return () => {
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve("" + delay);
+          // delay % 3 ? resolve("✅" + delay) : reject("❌" + delay);
+        }, delay);
+      });
+    };
+  }
+  const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000];
+  const tasks = times.map((item) => createTask(item));
+  console.log("[ tasks ]-141", tasks);
+  concurrencyRequest(tasks, 3).then((res) => {
+    console.log("[ res ]-143", res);
+  });

Web Worker

可以创建一个独立线程, 因为不会阻塞主线程运行,可以将比较耗费资源操作放在里面执行,比如耗时计算,可以通过 postMessage 进行线程间通信

js
// 主线程
+var worker = new Worker('worker.js')
+worker.postMessage([10, 24])
+worker.onmessage = function(e) {
+    console.log(e.data)
+}
+
+// Worker 线程
+onmessage = function (e) {
+    if (e.data.length > 1) {
+        postMessage(e.data[1] - e.data[0])
+    }
+}
+
+// 主线程
+worker.terminate()
// 主线程
+var worker = new Worker('worker.js')
+worker.postMessage([10, 24])
+worker.onmessage = function(e) {
+    console.log(e.data)
+}
+
+// Worker 线程
+onmessage = function (e) {
+    if (e.data.length > 1) {
+        postMessage(e.data[1] - e.data[0])
+    }
+}
+
+// 主线程
+worker.terminate()

在 Worker 线程中,self 和 this 都代表子线程的全局对象。对于监听 message 事件,以下的四种写法:

js
// 写法 1
+self.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 2
+this.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 3
+addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 4
+onmessage = function (e) {
+    // ...
+}
// 写法 1
+self.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 2
+this.addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 3
+addEventListener('message', function (e) {
+    // ...
+})
+
+// 写法 4
+onmessage = function (e) {
+    // ...
+}

Service Worker

服务器与浏览器之间的中间人,如果网站中注册了Service Worker那么它可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器,我们在Service Worker 中可以做拦截客户端的请求、向客户端发送消息、向服务器发起请求等先关操作,其中最重要且广泛的的作用就是离线资源缓存。

特性

  1. 基于web worker(JavaScript主线程的独立线程,如果执行消耗大量资源的操作也不会堵塞主线程)
  2. 在web worker的基础上增加了离线缓存的能力
  3. 本质上充当Web应用程序(服务器)与浏览器之间的代理服务器
  4. 创建有效的离线体验(将一些不常更新的内容缓存在浏览器,提高访问体验)
  5. 由事件驱动的,具有生命周期
  6. 可以访问cache和indexDB
  7. 支持消息推送
  8. 并且可以让开发者自己控制管理缓存的内容以及版本
  9. 可以通过 postMessage 接口把数据传递给其他JS 文件
  10. 更多无限可能

WARNING

不能访问 DOM、不能同步操作

`,16),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.lean.js" "b/assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.lean.js" new file mode 100644 index 00000000..0f80eb9e --- /dev/null +++ "b/assets/Interview_JavaScript_Promise\347\233\270\345\205\263.md.1015a7af.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/Promise相关.md","filePath":"Interview/JavaScript/Promise相关.md"}'),p={name:"Interview/JavaScript/Promise相关.md"},o=l("",16),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{i as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.js" "b/assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.js" new file mode 100644 index 00000000..a661a6c1 --- /dev/null +++ "b/assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.js" @@ -0,0 +1,91 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/原型与原型链.md","filePath":"Interview/JavaScript/原型与原型链.md"}'),p={name:"Interview/JavaScript/原型与原型链.md"},o=l(`

new 对象的执行过程

  1. 创建一个新对象:new操作符会创建一个新对象,该对象会继承自构造函数的原型对象。

  2. 设置对象的原型:新对象的__proto__属性会被设置为构造函数的原型对象prototype

  3. 执行构造函数:构造函数会被执行,this 指向新创建的对象。在构造函数内部,可以通过this关键字来添加属性和方法到新对象中。

  4. 对构造函数有返回值的处理判断:

    1. 如果构造函数没有显式地返回对象,返回新创建的对象;(基本类型忽略)
    2. 如果构造函数返回了一个对象,则返回该对象。(引用类型返回)
js
function Person(name, age) {
+  this.name = name;
+  this.age = age;
+}
+
+var person = new Person('Alice', 18);
+console.log(person); // { name: 'Alice', age: 18 }
+//new Person('Alice', 18)会创建一个新的对象,并执行Person函数,将this关键字指向新对象。最后返回新对象,赋值给变量person。
function Person(name, age) {
+  this.name = name;
+  this.age = age;
+}
+
+var person = new Person('Alice', 18);
+console.log(person); // { name: 'Alice', age: 18 }
+//new Person('Alice', 18)会创建一个新的对象,并执行Person函数,将this关键字指向新对象。最后返回新对象,赋值给变量person。

原型和原型链

作用:解决构造函数浪费内存问题,实现对象属性和方法的共享。

js
function Star(){
+
+}
+let star1 = new Star
+ star1.__proto__ === star1.constructor.prototype 
+ Star === Start.prototype.constructor
+ Object.prototype.__proto__ //null
+ Object instanceof Function   //Object顶级对象是 顶级构造器 Fcuntion 的实例
function Star(){
+
+}
+let star1 = new Star
+ star1.__proto__ === star1.constructor.prototype 
+ Star === Start.prototype.constructor
+ Object.prototype.__proto__ //null
+ Object instanceof Function   //Object顶级对象是 顶级构造器 Fcuntion 的实例

2023-03-03-14-31-082023-03-03-14-55-442023-03-03-16-50-56

函数的隐式原型对象

js
function test(){}
+test.__proto__ == Function.prototype   //ture
function test(){}
+test.__proto__ == Function.prototype   //ture

本身 ---> 构造函数.prototype(本身.__proto__) ---> 构造函数原型对象的原型.prototype.__proto__...--->Object.prototype ---> null

JS继承有哪些方式

方式一:ES6

js
class Parent{
+	constructor(){
+		this.age = 18;
+	}
+}
+
+class Child extends Parent{
+	constructor(){
+		super();
+		this.name = '张三';
+	}
+}
+let o1 = new Child();
+console.log( o1,o1.name,o1.age );
class Parent{
+	constructor(){
+		this.age = 18;
+	}
+}
+
+class Child extends Parent{
+	constructor(){
+		super();
+		this.name = '张三';
+	}
+}
+let o1 = new Child();
+console.log( o1,o1.name,o1.age );

方式二:原型链继承

js
function Parent(){
+	this.age = 20;
+}
+function Child(){
+	this.name = '张三'
+}
+//子构造函数原型对象指向父构造函数实例
+Child.prototype = new Parent();
+let o2 = new Child();
+console.log( o2,o2.name,o2.age );
function Parent(){
+	this.age = 20;
+}
+function Child(){
+	this.name = '张三'
+}
+//子构造函数原型对象指向父构造函数实例
+Child.prototype = new Parent();
+let o2 = new Child();
+console.log( o2,o2.name,o2.age );

方式三:借用构造函数继承

function Parent(){
+	this.age = 22;
+}
+function Child(){
+	this.name = '张三'
+	Parent.call(this);
+}
+let o3 = new Child();
+console.log( o3,o3.name,o3.age );
function Parent(){
+	this.age = 22;
+}
+function Child(){
+	this.name = '张三'
+	Parent.call(this);
+}
+let o3 = new Child();
+console.log( o3,o3.name,o3.age );
`,17),e=[o];function t(c,r,y,i,A,D){return n(),a("div",null,e)}const d=s(p,[["render",t]]);export{E as __pageData,d as default}; diff --git "a/assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.lean.js" "b/assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.lean.js" new file mode 100644 index 00000000..20374fc8 --- /dev/null +++ "b/assets/Interview_JavaScript_\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md.4ad216b5.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/原型与原型链.md","filePath":"Interview/JavaScript/原型与原型链.md"}'),p={name:"Interview/JavaScript/原型与原型链.md"},o=l("",17),e=[o];function t(c,r,y,i,A,D){return n(),a("div",null,e)}const d=s(p,[["render",t]]);export{E as __pageData,d as default}; diff --git "a/assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.js" "b/assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.js" new file mode 100644 index 00000000..4f91413c --- /dev/null +++ "b/assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.js" @@ -0,0 +1,377 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"常见基础面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/基础面试题.md","filePath":"Interview/JavaScript/基础面试题.md"}'),p={name:"Interview/JavaScript/基础面试题.md"},o=l(`

常见基础面试题

数据类型

原始类型:number,string,boolean,null,undefined,bigint,symbol

引用类型:Object

  • 标准普通对象:Object
  • 标准准特殊对象:Array,Date,Math,Error,RegExp
  • 非标准特殊对象(包装类型):Number,String,Boolean
  • 可执行对象:Function

Symbol应用

  1. 对象唯一值属性
  2. 唯一标识统一管理(pinia 中的 storeId)
  3. iterator底层实现机制

类型检测方式

  1. typeof:所有数据类型,在计算机底层都是按照‘64 位二进制’进行存储的, typeof是按照二进制值进行检测类型的
    详细转换机制
  2. 若二进制前三位是‘0’,并且实现了 call 方法,则返回 function,没有实现则返回 object
  3. null是 64 个 ‘0’,typeof null ---> 'object'(局限性)
  4. 检测未被声明的变量,返回 undefined :::
js
const isObj = option =>  option !== null && (typeof option === 'object' || typeof option === 'function')
const isObj = option =>  option !== null && (typeof option === 'object' || typeof option === 'function')

数据类型转换

其他类型转为数字类型

规则:

  1. 宇符串转换为数宇:空宇符串变为0,如果出现任何非有效数宇宇符,结果都是NaN

  2. 把布尔转换为数宇true->1 ; false->0

  3. null->0 ; undefined->NaN

  4. Symbol无法转换为数宇,会报错:Uncaught TypeError

  5. BigInt转为数字,会去除“n”(超过安全数宇的,会按照科学计数法处理)

  6. 把对象转换为数字

  • 先调用对線的 Symbol.toPrimitive 这个方法,如果不存在这个方法
  • 再调用对泉的 valueof 获取原始值,如果获取的值不是原始值,比如数组
  • 再调用对線的 toString 把其变为字符串
  • 最后再把宇符串基于Number方法转换为数字
js
parseInt(val,radix) parseFloat(val)
+parseInt(null)  parseInt(undefined) -> NaN
+/*  规则:val 必须是字符串,不是则自动转为字符串;
+      然后再 从左往右 找符合 radix(进制)有效数字,一个没找到则返回 NaN,
+      遇到一个非有效数字字符,则停止查找,并 parseInt(之前符合的字符串)  parseInt('12px') -> 12
+*/
parseInt(val,radix) parseFloat(val)
+parseInt(null)  parseInt(undefined) -> NaN
+/*  规则:val 必须是字符串,不是则自动转为字符串;
+      然后再 从左往右 找符合 radix(进制)有效数字,一个没找到则返回 NaN,
+      遇到一个非有效数字字符,则停止查找,并 parseInt(之前符合的字符串)  parseInt('12px') -> 12
+*/

2023-03-04-22-31-38

其他类型转为字符串

隐式转换:String(val)

js
let a = '10'
+let n = a++ // 10(数字)  ++a / a++ 一定是数字运算
+//+出现在左边,转换为数字    +'10'->10
let a = '10'
+let n = a++ // 10(数字)  ++a / a++ 一定是数字运算
+//+出现在左边,转换为数字    +'10'->10

2023-03-04-22-57-17

其他类型转为布尔类型

除了falsy值: 0、-0、NaN、null、undefined、空串,其余都是 true

相等与全等区别

相等(==):两边数据类型不同,会先进行类型转换,再进行比较

  1. 对象与字符串:对象转字符串 Symbol.toPrimitive -> valueOf -> toString,再比较
  2. null == undefined --> true ;null/undefined 与其他任何值都不相等
  3. 对象与对象,比较的是内存地址是否相同
  4. NaN 与其他,NaN 不与任何值相等,NaN == NaN --> false
  5. 除了以上情况,只要两边类型不一致,剩下的都是转为数字,再进行比较

全等(===):两个操作数类型相同,值也需相同才返回 true

可用==的情况:使用时相当于 obj.a === null || obj.a === undefined

  1. 判断对象的属性是否存在 obj.a == null
  2. 判断函数的参数是否存在 arg == null
面试题
js
//题1:
+[] == false   -> 0 == 0   -> false
+![] == false  -> false == false   -> true
+
+//题2:
+var a = ?;
+if(a == 1 && a == 2 && a == 3){
+  console.log('OK')
+}
+//解法一:利用==会进行类型转换,对象转为数字会经历:
+//Symbol.toPrimitive -> valueOf -> toString
+var a = {
+  i: 0,
+  [Symbol.toPrimitive](){
+    return ++this.i
+  }
+}
+//解法二:重写 toString
+var a = [1, 2, 3]
+a.toString = a.shift
+
+//解法三: 数据劫持
+var i = 0
+Object.defineProperty(window, 'a', {
+  get(){
+    return ++i
+  }
+})
//题1:
+[] == false   -> 0 == 0   -> false
+![] == false  -> false == false   -> true
+
+//题2:
+var a = ?;
+if(a == 1 && a == 2 && a == 3){
+  console.log('OK')
+}
+//解法一:利用==会进行类型转换,对象转为数字会经历:
+//Symbol.toPrimitive -> valueOf -> toString
+var a = {
+  i: 0,
+  [Symbol.toPrimitive](){
+    return ++this.i
+  }
+}
+//解法二:重写 toString
+var a = [1, 2, 3]
+a.toString = a.shift
+
+//解法三: 数据劫持
+var i = 0
+Object.defineProperty(window, 'a', {
+  get(){
+    return ++i
+  }
+})

怎么解决精度问题

根本原因:所有数据类型在计算机底层都是以64位二进制存储的,可能出现无限循环,超过 64 位部分被丢弃

  1. 将数字转为整数【扩大系数法】
  2. 第三方库:Math.js, decimal.js, big.js

var/let/const 区别

varletconst
变量提升支持不支持不支持
块级作用域没有
暂存性死区没有存在存在
能否修改变量的值不能修改
变量的值不能修改允许不允许不允许

函数声明会覆盖其他的同名的变量声明。如果有多个函数声明,则是由最后的一个函数声明覆盖之前所有的声明。

const

  1. 声明必须初始化

  2. 只读常量,变量的值不能修改

    • 简单类型 :值就保存在变量指向的那个内存地址,等同于常量。

    • 引用类型:变量指向的内存地址,保存的只是一个指向实际数据的指针;

      const 只能保证指针固定,不能控制指向的数据结构。

暂存性死区

暂存性死区

暂存性死区:使用 let / const 定义该变量之前的区域,

不能在声明前访问,作用域内被声明,不受外部影响

基于 let/const 变量声明,在词法解析阶段就已经明确了未来上下文中必定会有相关变量声明;

如果在声明前使用,则报错 Uncaught ReferenceError

this指向

  1. 全局作用域中或者普通函数中指向全局对象window
  2. 立即执行函数必定指向window
  3. 构造函数中指向对象实例
  4. 事件绑定指向事件源对象
  5. 方法中谁调用就指向谁
  6. 定时器回调为普通函数指向window,箭头函数指向声明时所在外部作用域
  7. forEach等回调函数默认指向window,指定第二个参数存在则指向第二个参数
  8. 严格模式指向window的变为undefined

防抖与节流

防抖:频繁触发某个事件时,在设定的时间内再次触发,会重新清除上一次定时器,重新开启定时器开始计时。

节流:频繁触发某个事件时,保证设定的时间内只会执行一次,只有等执行完才会打开节流阀执行下一个事件。

防抖

js
//实现原理:每次触发事件时,取消之前的定时器,重新计时
+function debounce(func,delay = 500){
+
+  let timer = null
+  return function(...args){
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      func.apply(this,args)
+    },delay)
+  }
+}
//实现原理:每次触发事件时,取消之前的定时器,重新计时
+function debounce(func,delay = 500){
+
+  let timer = null
+  return function(...args){
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      func.apply(this,args)
+    },delay)
+  }
+}
防抖拓展写法
js
function debounce(func,delay = 500immediate=false){
+  //参数判断处理
+	if(typeof func !== 'function') throw new TypeError('func is not a funciton')
+  //debounce(func,true)
+  if(typeof delay === 'boolean'){
+     immediate = delay
+     delay = undefined
+  }
+  isNaN(delay = +delay) ? 500 : delay	//若不是数字则默认 500
+	if(typeof immediate !== 'boolean') immediate = false
+  
+  let timer = null
+  return function(...args){
+    //第一次自执行完,timer 已经有值,
+    let now = !timer && immediate
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      //结束边界触发
+      if(!immediate) func.apply(this,args)
+      //清除最后一个定时器
+      timer = clearTimeout(timer)
+    },delay)
+    //若为立即执行,则第一次,开启边界触发
+    if(now) func.apply(this,args)
+  }
+}
function debounce(func,delay = 500immediate=false){
+  //参数判断处理
+	if(typeof func !== 'function') throw new TypeError('func is not a funciton')
+  //debounce(func,true)
+  if(typeof delay === 'boolean'){
+     immediate = delay
+     delay = undefined
+  }
+  isNaN(delay = +delay) ? 500 : delay	//若不是数字则默认 500
+	if(typeof immediate !== 'boolean') immediate = false
+  
+  let timer = null
+  return function(...args){
+    //第一次自执行完,timer 已经有值,
+    let now = !timer && immediate
+    if(timer) clearTimeout(timer) //清除上一次
+    timer = setTimeout(() =>{
+      //结束边界触发
+      if(!immediate) func.apply(this,args)
+      //清除最后一个定时器
+      timer = clearTimeout(timer)
+    },delay)
+    //若为立即执行,则第一次,开启边界触发
+    if(now) func.apply(this,args)
+  }
+}

节流

js
//实现原理:每次触发事件时,判断当前是否存在等待执行的延时函数
+//方法一:定时器存在则什么都不做
+function throttle(func,delay){
+  let timer = null
+  return function(...args){
+    if(timer) return 
+    timer = setTimeout(()=>{
+      func.apply(this,...args)
+      timer = null
+    }, delay)
+  }
+}
+//方法二:
+function throttle(func,delay){
+  let flag = true //节流阀:开启状态
+  return function(...args){
+    if(!flag) return 
+    flag = false //已经在处理:关闭
+    setTimeout(() =>{
+      func.apply(this,args)
+      flag = true //处理完:重新打开
+    },delay)
+  }
+  }
+//实现三:当前时间-上次执行时间 > 设定时间,才执行
+funtion throttle(func,delay){
+  let start = 0
+  return function(...args){
+    let now = Data.now()
+    if(now - start > delay){
+       func.apply(this,args)
+   		 start = now
+    }
+  }
+}
//实现原理:每次触发事件时,判断当前是否存在等待执行的延时函数
+//方法一:定时器存在则什么都不做
+function throttle(func,delay){
+  let timer = null
+  return function(...args){
+    if(timer) return 
+    timer = setTimeout(()=>{
+      func.apply(this,...args)
+      timer = null
+    }, delay)
+  }
+}
+//方法二:
+function throttle(func,delay){
+  let flag = true //节流阀:开启状态
+  return function(...args){
+    if(!flag) return 
+    flag = false //已经在处理:关闭
+    setTimeout(() =>{
+      func.apply(this,args)
+      flag = true //处理完:重新打开
+    },delay)
+  }
+  }
+//实现三:当前时间-上次执行时间 > 设定时间,才执行
+funtion throttle(func,delay){
+  let start = 0
+  return function(...args){
+    let now = Data.now()
+    if(now - start > delay){
+       func.apply(this,args)
+   		 start = now
+    }
+  }
+}

应用

​ 防抖:输入框搜索、编辑框实时保存,(手机息屏策略,王者荣耀回城操作)

​ 节流:滚动到底部加载更多、图标跟随鼠标(地铁发车时间,王者荣耀技能冷却)

前端本地存储方式

区别

存储大小存储时间同源策略在同一浏览器的相同域名、不同端口号下
localStorage5M键值对以字符串形式存储,数据长期保留,不主动删除一直存在受限制不可以共享
sessionStorage5M会话结束自动清除(浏览器窗口关闭时)协议隔离跳转的页面可以共享
cookie4kb设置到期时间,过期清除受限制可以共享

用法

localStorage

js
localStorage.setItem('key', 'value');   //添加数据
+let val = localStorage.getItem('key');  //读取数据
+localStorage.removeItem('key');         //移除单个
+localStorage.clear();                   //移除所有
localStorage.setItem('key', 'value');   //添加数据
+let val = localStorage.getItem('key');  //读取数据
+localStorage.removeItem('key');         //移除单个
+localStorage.clear();                   //移除所有

sessionStorage

js
sessionStorage.setItem('key', 'value');  // 保存数据到 sessionStorage
+let data = sessionStorage.getItem('key');//获取数据
+sessionStorage.removeItem('key');        //删除
+sessionStorage.clear();                  //删除所有
sessionStorage.setItem('key', 'value');  // 保存数据到 sessionStorage
+let data = sessionStorage.getItem('key');//获取数据
+sessionStorage.removeItem('key');        //删除
+sessionStorage.clear();                  //删除所有

cookie

js
let cookies = document.cookie           //同源下获取所有cookie
+document.cookie = 'key=value'           //添加
+document.cookie = "key=; expires=xxx"; 	//设定到期时间自动清除
let cookies = document.cookie           //同源下获取所有cookie
+document.cookie = 'key=value'           //添加
+document.cookie = "key=; expires=xxx"; 	//设定到期时间自动清除

IndexedDB

Generator

一是,function关键字与函数名之间有一个星号;

二是,函数体内部使用yield表达式,定义不同的内部状态。

js
function* helloWorldGenerator() {
+  let a = yield 'hello';
+  console.log(a) //123
+  let b = yield 'world';
+  console.log(b) //undefined
+  return 'ending';
+}
+
+var hw = helloWorldGenerator();
+hw.next()
+hw.next(123) //a = 123
function* helloWorldGenerator() {
+  let a = yield 'hello';
+  console.log(a) //123
+  let b = yield 'world';
+  console.log(b) //undefined
+  return 'ending';
+}
+
+var hw = helloWorldGenerator();
+hw.next()
+hw.next(123) //a = 123

nex()传参会赋值给上一次yield的的返回值

异步流程同步化

js
function* test(){
+  let res1 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第一秒执行')
+    },1000)
+  })
+  console.log(res1) //第一秒执行
+  
+   let res2 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第二秒执行')
+    },1000)
+  })
+}
+
+function generatorRunner(fn){
+	let generator = fn()
+  let step = generator.next()
+  //定义递归函数
+  function loop(stepArg,generator){
+    //获取本次 yield 右侧的结果
+    let value = stepArg.value
+    if(value instanceof Promise){
+      //如果是 Promise 对象就在 then 函数的回调中获取本次程序结果
+      //并且等待回调执行的时候进入下一次递归
+      value.then((function(promiseValue){
+        if(!stepArg.done){
+          loop(generator.next(promiseValue),generator)
+        }
+      }
+    }else{
+          //判断程序没有执行完就将本次结果传入下一步进入下一次递归
+  		if(!stepArg.done) loop(generator.next(stepArg.value),generator)
+ 	}
+  }
+  loop(step,generator)
+}
function* test(){
+  let res1 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第一秒执行')
+    },1000)
+  })
+  console.log(res1) //第一秒执行
+  
+   let res2 = yield new Promise((resolve) =>{
+    setTimeout(function(){
+      resolve('第二秒执行')
+    },1000)
+  })
+}
+
+function generatorRunner(fn){
+	let generator = fn()
+  let step = generator.next()
+  //定义递归函数
+  function loop(stepArg,generator){
+    //获取本次 yield 右侧的结果
+    let value = stepArg.value
+    if(value instanceof Promise){
+      //如果是 Promise 对象就在 then 函数的回调中获取本次程序结果
+      //并且等待回调执行的时候进入下一次递归
+      value.then((function(promiseValue){
+        if(!stepArg.done){
+          loop(generator.next(promiseValue),generator)
+        }
+      }
+    }else{
+          //判断程序没有执行完就将本次结果传入下一步进入下一次递归
+  		if(!stepArg.done) loop(generator.next(stepArg.value),generator)
+ 	}
+  }
+  loop(step,generator)
+}

requestAnimationFrame

60HZ/1000ms = 16.67ms(显示屏每毫秒刷新频率)

起因:setTimeout/setInterval是异步 API,设置的时间间隔没办法保证。

解决:为了设置更精确动画时间间隔、达到平滑动画效果。用法类似 setTimeout API, 本质采用的是系统时间间隔,而不是 JS 执行时间间隔。

希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

用法2023-03-02-15-53-32

浅拷贝和深拷贝

解释

浅拷贝:只拷贝一层,属性为对象时只复制值,不复制对象本身,指向同一对象 深拷贝:完全拷贝一份新的,新对象更改不会影响到旧对象

浅拷贝

js
let newObj = Object.assign({},obj) //只拷贝对象自身的可枚举的属性
+let newObj = [...obj]
+
+//数组
+Array.prototype.slice()
+Array.prototype.concat()
+
+let arr = [
+  {
+    name:'zhan',
+    age:23
+  },
+  123,
+  456
+]
+let newArr1 = arr.slice()
+let newArr2 = arr.concat()
+//改变内部的引用类型两者都会有影响
let newObj = Object.assign({},obj) //只拷贝对象自身的可枚举的属性
+let newObj = [...obj]
+
+//数组
+Array.prototype.slice()
+Array.prototype.concat()
+
+let arr = [
+  {
+    name:'zhan',
+    age:23
+  },
+  123,
+  456
+]
+let newArr1 = arr.slice()
+let newArr2 = arr.concat()
+//改变内部的引用类型两者都会有影响
js
//方式一:
+//会忽略undefined,function,RegExp,Date
+let newObj = JSON.parse(JSON.stringify(obj))
+
+//方式二:
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}
//方式一:
+//会忽略undefined,function,RegExp,Date
+let newObj = JSON.parse(JSON.stringify(obj))
+
+//方式二:
+function deepClone(obj){
+  if(obj === null || typeof obj !== 'object') return obj
+  if(obj.constructor === Date) return new Date(obj); 
+  if(obj.constructor === RegExp) return new RegExp(obj);
+  let newObj = Array.isArray(obj) ? [] : {}
+  for(let key in obj){
+    if(obj.hasOwnProperty(key)) newObj[key] =  deepClone(obj[key])
+  }
+  return newObj
+}

事件捕获和冒泡机制

事件传播过程:事件捕获 ---> 目标阶段---> 事件冒泡

事件捕获:从根元素(html)向内传播,直到目标元素,途中会触发绑定事件捕获元素的回调。element.addEventListener(event, function, true)

事件冒泡:从目标元素向外传播,直到根元素,途中会触发绑定事件冒泡元素的回调。onclickaddEventListener默认绑定冒泡阶段。

阻止冒泡:event.stopPropagation()

阻止默认行为:event.preventDefault(),例如:a标签跳转,表单按钮数据提交至服务器。

阻止同一节点其他后绑定事件执行:event.stopImmediatePropagation()

Promise链式调用

是指在一个Promise对象上多次调用then方法,每个then方法都可以接收上一个Promise对象的返回值,

并返回一个新的Promise对象,从而形成一个Promise链 ,从而实现多个异步操作的顺序执行和数据传递。

如果then方法中抛出了异常,那么后续的then方法会被跳过,直接执行catch方法。

如果then方法中返回了一个Promise对象,那么后续的then方法会等待该Promise对象的状态发生改变后再执行。

可以避免回调地狱,使得代码更加清晰易读。

`,93),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.lean.js" "b/assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.lean.js" new file mode 100644 index 00000000..8dcd882c --- /dev/null +++ "b/assets/Interview_JavaScript_\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md.0df982a7.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"常见基础面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/基础面试题.md","filePath":"Interview/JavaScript/基础面试题.md"}'),p={name:"Interview/JavaScript/基础面试题.md"},o=l("",93),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.js" "b/assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.js" new file mode 100644 index 00000000..4c885c35 --- /dev/null +++ "b/assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.js" @@ -0,0 +1,33 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/字符串常用方法.md","filePath":"Interview/JavaScript/字符串常用方法.md"}'),o={name:"Interview/JavaScript/字符串常用方法.md"},p=l(`

字符串常用方法

都不会影响原字符串:因为字符串是不可变的!

  1. 增删改:replace,replaceAll

  2. 增:repeat,concat,padStart,padEnd

  3. 删:substr,substring,slice,trim,trimStart,trimEnd

  4. 改:split,toLowerCase,toUpperCase,toLocaleLowerCase,

    toLocaleUpperCase, String.fromCharCode()

  5. 查:valueOf,at,charAt,charCodeAt,indexOf,lastIndexOf,

    search,includes,match,startsWith,endsWith

charCodeAt与fromCharCode

js
'ABC'.charCodeAt(2)  //67 返回指定索引位的 ASCII 码
+String.fromCharCode(65, 66, 67) //'ABC' 返回 ASCII 码对应的字符
'ABC'.charCodeAt(2)  //67 返回指定索引位的 ASCII 码
+String.fromCharCode(65, 66, 67) //'ABC' 返回 ASCII 码对应的字符

slice 与 substring区别

slice 与 substring

slice 结束索引大于等于 0 时且小于起始索引时,返回空;结束索引大于0从前面计数,小于0从后面计数的原则。

substring 中如果结束索大于起始索引,则会自动将其调换后截取,当参数小于0 时按0处理。

js
let y = "www.map.baidu.com";
+console.log(y.slice(4,11)); //map.bai
+console.log(y.slice(11,4)); //''
+console.log(y.slice(3,-4)); //.map.baidu
+console.log(y.slice(3,0)); //''
+console.log(y.slice(4)); //map.baidu.com
+
+let y = "www.map.baidu.com";
+console.log(y.substring(4,11)); //map.bai
+console.log(y.substring(11,4)); //map.bai
+console.log(y.substring(3,-4)); //www
+console.log(y.substring(3,0)); //www
+console.log(y.substring(4)); //map.baidu.com
let y = "www.map.baidu.com";
+console.log(y.slice(4,11)); //map.bai
+console.log(y.slice(11,4)); //''
+console.log(y.slice(3,-4)); //.map.baidu
+console.log(y.slice(3,0)); //''
+console.log(y.slice(4)); //map.baidu.com
+
+let y = "www.map.baidu.com";
+console.log(y.substring(4,11)); //map.bai
+console.log(y.substring(11,4)); //map.bai
+console.log(y.substring(3,-4)); //www
+console.log(y.substring(3,0)); //www
+console.log(y.substring(4)); //map.baidu.com

valueOf 与 toString 的异同

共同点

都是对象的方法,用于将对象转换成可操作的基本类型值。

valueOftoString
返回值原始值或对象本身对象转换成可阅读的字符串
能否接受参数转换基数不可以可以,返回不同进制的字符串形式的数值
Date类型返回现在到1970年1月1日的毫秒数时间的字符串

undefinednull 都没有toString() valueOf() 方法

Object.prototype.toString.toString() 能够很好的判断数据的类型及内置对象

js
Number(10).toString(2)	//'1010'
+Number(10).valueOf(2)		//10
+new Date().toString()		//'Thu Mar 02 2023 11:39:56 GMT+0800 (中国标准时间)'
+new Date().valueOf() 		//1677728421211
Number(10).toString(2)	//'1010'
+Number(10).valueOf(2)		//10
+new Date().toString()		//'Thu Mar 02 2023 11:39:56 GMT+0800 (中国标准时间)'
+new Date().valueOf() 		//1677728421211
`,15),e=[p];function t(c,r,y,A,i,D){return a(),n("div",null,e)}const B=s(o,[["render",t]]);export{C as __pageData,B as default}; diff --git "a/assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.lean.js" "b/assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.lean.js" new file mode 100644 index 00000000..3c71c69c --- /dev/null +++ "b/assets/Interview_JavaScript_\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md.4808f793.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const C=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/字符串常用方法.md","filePath":"Interview/JavaScript/字符串常用方法.md"}'),o={name:"Interview/JavaScript/字符串常用方法.md"},p=l("",15),e=[p];function t(c,r,y,A,i,D){return a(),n("div",null,e)}const B=s(o,[["render",t]]);export{C as __pageData,B as default}; diff --git "a/assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.js" "b/assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.js" new file mode 100644 index 00000000..aabd530a --- /dev/null +++ "b/assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.js" @@ -0,0 +1,399 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"常见进阶面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/进阶面试题.md","filePath":"Interview/JavaScript/进阶面试题.md"}'),p={name:"Interview/JavaScript/进阶面试题.md"},o=l(`

常见进阶面试题

模块化

JS运行的环境全局对象
浏览器window直接支持ES6Module,但是不支持CommonJS
Nodeglobal支持CommonJS,但是不支持ES6Module
WebpackCommon JS&ES6Module都支持,支持相互之间的“混用
Vite基于ES6Module规范,实现模块之间的相互引用

闭包

闭包:作用域的一种特殊应用,内层函数作用域用到了外层函数作用域的变量。由于被内层函数引用,导致外层函数执行完变量不会被释放,就形成了闭包。

闭包案例
js
function func(){
+  const val = 10 
+  return function(){
+    console.log(val)
+  }
+}
+const val = 100
+const fn = func()
+fn()//10
function func(){
+  const val = 10 
+  return function(){
+    console.log(val)
+  }
+}
+const val = 100
+const fn = func()
+fn()//10
js
function fn(){
+  const data = {}
+  return {
+    set: function(key,val){
+      data[key] = val
+    }
+    get:function(key){
+      return data[key]
+    }
+  }
+}
+const handle = fn()
+handle.set('name','zhangsan')
+handle.get('name')
function fn(){
+  const data = {}
+  return {
+    set: function(key,val){
+      data[key] = val
+    }
+    get:function(key){
+      return data[key]
+    }
+  }
+}
+const handle = fn()
+handle.set('name','zhangsan')
+handle.get('name')
js
const btns = document.querySelectorAll('.btn') //5个按钮
+for(val i = 0;i < btns.length; i++){	//改用 let 形成闭包
+	btns[i].onclick = function(){
+    console.log(i) //输出结果都是 5
+  } 
+}
+//==>
+for(val i = 0;i < btns.length; i++){
+(function(){
+ btns[i].onclick = function(){
+      console.log(i) //输出结果: 01234
+  }})(i)
+}
const btns = document.querySelectorAll('.btn') //5个按钮
+for(val i = 0;i < btns.length; i++){	//改用 let 形成闭包
+	btns[i].onclick = function(){
+    console.log(i) //输出结果都是 5
+  } 
+}
+//==>
+for(val i = 0;i < btns.length; i++){
+(function(){
+ btns[i].onclick = function(){
+      console.log(i) //输出结果: 01234
+  }})(i)
+}

应用

  1. 函数柯里化
  2. 变量私有化

弊端

过度使用闭包会造成内存占用过多,容易造成内存泄漏,手动清空可解决问题。

函数柯里化

数组求和
js
let arr = [1,2,3,4]
+//方法一:
+let sum = arr.reduce((pre,cur) => pre + cur,0)
+//方法二:
+eval(arr.join('+'))
let arr = [1,2,3,4]
+//方法一:
+let sum = arr.reduce((pre,cur) => pre + cur,0)
+//方法二:
+eval(arr.join('+'))
实现 add(1,2)(3)
js
const add = function(...params){ // params:[1,2]
+  return function(...args){ //args:[3]
+    return params.concat(args).reduce((pre,cur) => cur+pre)
+  }
+}
+//简化
+const add = (...params) => (...args) => params.concat(args).reduce((pre,cur) => pre + cur)
const add = function(...params){ // params:[1,2]
+  return function(...args){ //args:[3]
+    return params.concat(args).reduce((pre,cur) => cur+pre)
+  }
+}
+//简化
+const add = (...params) => (...args) => params.concat(args).reduce((pre,cur) => pre + cur)
实现 add(1)(2)(3)
js
const add = function(a){
+  return function(b){
+    return function(c){
+      return a + b + c
+    }
+  }
+}
+//简化
+const add = a => b => c => a + b + c 
+
+//柯里化:curring 函数
+const curring = function(){
+  let params = []//利用闭包存储实参
+  const add = (...args) =>{
+    params = params.concat(args)
+    return add
+  }
+  //在对象转数字过程中,进行求和处理
+  add[Symbol.toPrimitive] = () => {
+    return params.reduce((pre,cur) => pre + cur)
+  }
+  return add
+}
+const add = curring()
+let sum = add(1)(2)(3)(4)(5)(6)
+alert(sum) //21
+console.log(+sum)//21
const add = function(a){
+  return function(b){
+    return function(c){
+      return a + b + c
+    }
+  }
+}
+//简化
+const add = a => b => c => a + b + c 
+
+//柯里化:curring 函数
+const curring = function(){
+  let params = []//利用闭包存储实参
+  const add = (...args) =>{
+    params = params.concat(args)
+    return add
+  }
+  //在对象转数字过程中,进行求和处理
+  add[Symbol.toPrimitive] = () => {
+    return params.reduce((pre,cur) => pre + cur)
+  }
+  return add
+}
+const add = curring()
+let sum = add(1)(2)(3)(4)(5)(6)
+alert(sum) //21
+console.log(+sum)//21

compose

思想:利用闭包预先存储,供其夏季上下文后期使用,可解决函数嵌套导致的可读性差问题。

js
const add1 = x => x + 1
+const mul3 = x => x * 3
+const div2 = x => x / 2
+//不使用柯里化:div2(mul3(add1(10)))
+
+const compose = function(...funcs){
+  //考虑不传函数,返回operate传的实参
+  let len = funcs.length
+  if(len === 0) return x => x
+  if(len === 1) return funcs[0]
+  return function operate(x){
+    return funcs.reduceRight((x,func) => func(x),x)
+  }
+}
+//不传函数
+const operate = compose()
+operate(10) //10
+//传一个
+const operate = compose(add1)
+operate(10) //11
+// 传多个
+const operate = compose(div2,mul3,add1,add1)
+operate(10) //18
const add1 = x => x + 1
+const mul3 = x => x * 3
+const div2 = x => x / 2
+//不使用柯里化:div2(mul3(add1(10)))
+
+const compose = function(...funcs){
+  //考虑不传函数,返回operate传的实参
+  let len = funcs.length
+  if(len === 0) return x => x
+  if(len === 1) return funcs[0]
+  return function operate(x){
+    return funcs.reduceRight((x,func) => func(x),x)
+  }
+}
+//不传函数
+const operate = compose()
+operate(10) //10
+//传一个
+const operate = compose(add1)
+operate(10) //11
+// 传多个
+const operate = compose(div2,mul3,add1,add1)
+operate(10) //18

闭包惰性思想

js
function getCss(ele, attr){
+  //加载判断样式兼容问题,没有更换刷新浏览器每次都需要做多余的判断
+  if(window.getComputedStyle){
+      return window.getComputedStyle(ele)[attr]
+  }else{
+      return window.getCurrentStyle(ele)[attr]
+  }
+}
+//优化后
+function getCss(ele, attr){
+  //第一次运行,根据兼容情况,重构 getCss
+  if(window.getComputedStyle){
+    getCss = function(ele, attr){
+      return window.getComputedStyle(ele)[attr]
+    }
+  }else{
+    getCss = function(ele, attr){
+      return window.getCurrentStyle(ele)[attr]
+    }
+  }
+  return getCss(ele, attr)
+}
+getCss(body, 'width')
+getCss(body, 'padding')
function getCss(ele, attr){
+  //加载判断样式兼容问题,没有更换刷新浏览器每次都需要做多余的判断
+  if(window.getComputedStyle){
+      return window.getComputedStyle(ele)[attr]
+  }else{
+      return window.getCurrentStyle(ele)[attr]
+  }
+}
+//优化后
+function getCss(ele, attr){
+  //第一次运行,根据兼容情况,重构 getCss
+  if(window.getComputedStyle){
+    getCss = function(ele, attr){
+      return window.getComputedStyle(ele)[attr]
+    }
+  }else{
+    getCss = function(ele, attr){
+      return window.getCurrentStyle(ele)[attr]
+    }
+  }
+  return getCss(ele, attr)
+}
+getCss(body, 'width')
+getCss(body, 'padding')

深度优先和广度优先

js
//数据
+let tree =  {
+    id: '1',
+    title: '节点1',
+    children: [
+      {
+        id: '1-1',
+        title: '节点1-1'
+      },
+      {
+        id: '1-2',
+        title: '节点1-2',
+        children: [{
+          id: '2',
+          title: '节点2',
+          children: [
+            {
+              id: '2-1',
+              title: '节点2-1'
+            }
+          ]
+        }]
+      }
+    ]
+  }
//数据
+let tree =  {
+    id: '1',
+    title: '节点1',
+    children: [
+      {
+        id: '1-1',
+        title: '节点1-1'
+      },
+      {
+        id: '1-2',
+        title: '节点1-2',
+        children: [{
+          id: '2',
+          title: '节点2',
+          children: [
+            {
+              id: '2-1',
+              title: '节点2-1'
+            }
+          ]
+        }]
+      }
+    ]
+  }

深度优先遍历(DFS)

深度优先遍历(DFS)是一种递归或栈的思想来遍历所有节点的算法。在 JavaScript 中,可以使用递归或栈来实现 DFS。具体步骤如下:

  1. 访问根节点
  2. 对根节点的所有子节点,依次执行以下操作:
    • 访问该子节点
    • 对该子节点的所有子节点,依次执行以上两步操作

JavaScript 中 DFS 的时间复杂度为 O(n),其中 n 是节点数。空间复杂度为 O(h),其中 h 是树的高度。

js
//递归方式
+let dfs = (node, nodes = []) => {
+  if (node) {
+    nodes.push(node.id)
+    node.children?.forEach(child =>	dfs(child, nodes) )
+  }
+  return nodes
+}
//递归方式
+let dfs = (node, nodes = []) => {
+  if (node) {
+    nodes.push(node.id)
+    node.children?.forEach(child =>	dfs(child, nodes) )
+  }
+  return nodes
+}
js
//非递归方式
+let dfs = (node) => {
+  let nodes = []
+  let stack = []
+  if(node){
+    stack.push(node)
+    while(stack.length){
+      let item = stack.shift()
+      let children = item.children
+      nodes.push(item.id)
+      children?.forEach(child => stack.push(child) )
+    }
+  }
+  return nodes
+}
//非递归方式
+let dfs = (node) => {
+  let nodes = []
+  let stack = []
+  if(node){
+    stack.push(node)
+    while(stack.length){
+      let item = stack.shift()
+      let children = item.children
+      nodes.push(item.id)
+      children?.forEach(child => stack.push(child) )
+    }
+  }
+  return nodes
+}
js
// 用非递归方式实现二叉树深度优先遍历
+function dfs(node) {
+  let nodes = [];
+  if (node) {
+    nodes.push(node);
+    node.children?.forEach(child => nodes = nodes.concat(dfs(child)))
+  }
+  return nodes;
+}
// 用非递归方式实现二叉树深度优先遍历
+function dfs(node) {
+  let nodes = [];
+  if (node) {
+    nodes.push(node);
+    node.children?.forEach(child => nodes = nodes.concat(dfs(child)))
+  }
+  return nodes;
+}

广度优先遍历(BFS)

广度优先遍历(BFS)是一种逐层扫描节点的算法。在 JavaScript 中,可以使用队列来实现 BFS。具体步骤如下:

  1. 将根节点入队
  2. 当队列非空时,执行以下操作:
    • 将队头节点出队,并访问该节点
    • 将该节点的所有子节点入队

JavaScript 中 BFS 的时间复杂度为 O(n),其中 n 是节点数。空间复杂度为 O(w),其中 w 是树的宽度。

js
function bfs(root) {
+  let nodes = []
+  const queue = [root];
+  while (queue.length > 0) {
+    const node = queue.shift();
+    nodes.push(node.id)
+    node.children?.forEach(child => {
+      queue.push(child);
+    });
+  }
+  return nodes
+}
+
+//简化后
+function bfs(root){
+  let nodes = []
+  let node,queue = [root]
+  while(node = queue.shift()){
+    nodes.push(node.id)
+    node.children && queue.push(...node.children)
+  }
+  return nodes
+}
function bfs(root) {
+  let nodes = []
+  const queue = [root];
+  while (queue.length > 0) {
+    const node = queue.shift();
+    nodes.push(node.id)
+    node.children?.forEach(child => {
+      queue.push(child);
+    });
+  }
+  return nodes
+}
+
+//简化后
+function bfs(root){
+  let nodes = []
+  let node,queue = [root]
+  while(node = queue.shift()){
+    nodes.push(node.id)
+    node.children && queue.push(...node.children)
+  }
+  return nodes
+}
js
function bfs(node) {
+  let nodes = []
+  if (node !== null) {
+    nodes.push(node)
+    let i = 0
+    while (node = nodes[i++]) {
+      node.children && nodes.push(...node.children)
+    }
+  }
+  return nodes
+}
function bfs(node) {
+  let nodes = []
+  if (node !== null) {
+    nodes.push(node)
+    let i = 0
+    while (node = nodes[i++]) {
+      node.children && nodes.push(...node.children)
+    }
+  }
+  return nodes
+}

两者的区别

  • 广度优先遍历需要使用队列逐层扫描节点,而深度优先遍历需要使用递归或栈来遍历节点。
  • 广度优先遍历的空间复杂度比深度优先遍历高,因为广度优先遍历需要使用队列来存储节点,而深度优先遍历只需要使用递归或栈。

广度优先遍历的应用

广度优先遍历可以用于许多问题,例如:

  • 查找最短路径:遍历距离起点最近的节点。
  • 查找连通块:可以找到由相邻节点组成的连通块。
  • 查找图的最小生成树

深度优先遍历的应用

  • 查找连通块:可以找到由相邻节点组成的连通块。
  • 查找拓扑排序:可以找到图的拓扑排序,即节点的一个线性序列,使得对于每个有向边 (u,v),都有 u 在序列中排在 v 的前面。
  • 查找强联通分量:通过深度优先遍历,可以找到图的强联通分量,即任意两点之间都存在一条路径的最大子图。

图文详解深度优先,广度优先遍历

loader和plugin区别

Loader

是用来处理单个模块的转换,将各种类型的文件(如 js、css、sass、less、图片等)转换为 Webpack 可以处理的模块;

执行顺序是从后往前依次执行,每个 Loader 都会对文件进行处理,直到最后一个 Loader 将文件转换为模块。

Plugin

是扩展 Webpack 功能的函数,可以在构建过程中执行一系列的任务,遍历所有的 Plugin,并执行它们的 apply 方法。

例如生成 HTML 文件(HtmlWebpackPlugin)、压缩代码(UglifyJsPlugin)、提取公共代码等。

Plugin 在 Loader 执行完成之后执行,可以访问 Webpack 的内部环境,并对其进行修改和优化。

前端模块化规范

前端模块化规范是为了解决前端代码复杂度、可维护性和可扩展性等问题而产生的。目前常用的前端模块化规范有CommonJS、AMD、CMD和ES6 Module等,它们之间的区别如下:

CommonJS规范:主要用于服务器端的JavaScript编程,Node.js采用了该规范。采用同步加载模块的方式,即在需要使用某个模块时,通过require函数同步加载该模块,然后才能执行后续代码。

ES6 Module:是ECMAScript 6标准中新增的模块化规范。 采用静态加载模块的方式,即在编译时就确定模块之间的依赖关系,然后再执行代码。

与其他模块化规范不同的是,ES6 Module不需要使用特定的函数或语法来定义和导入模块,而是使用import和export关键字来实现。

`,50),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.lean.js" "b/assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.lean.js" new file mode 100644 index 00000000..24dec29a --- /dev/null +++ "b/assets/Interview_JavaScript_\350\277\233\351\230\266\351\235\242\350\257\225\351\242\230.md.c89e986d.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"常见进阶面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/进阶面试题.md","filePath":"Interview/JavaScript/进阶面试题.md"}'),p={name:"Interview/JavaScript/进阶面试题.md"},o=l("",50),e=[o];function c(t,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{E as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.js" "b/assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.js" new file mode 100644 index 00000000..e9931629 --- /dev/null +++ "b/assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.js" @@ -0,0 +1,99 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"常见高级面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/高级面试题.md","filePath":"Interview/JavaScript/高级面试题.md"}'),p={name:"Interview/JavaScript/高级面试题.md"},o=l(`

常见高级面试题

怎么禁止下载图片(midjourney实现)

方案一:禁止右键

html
<img src="image.png" oncontextmenu="return false;" />
<img src="image.png" oncontextmenu="return false;" />
js
window.onload = function() {
+    document.oncontextmenu = function(event) {
+        event.returnValue = false;
+    };
+}
window.onload = function() {
+    document.oncontextmenu = function(event) {
+        event.returnValue = false;
+    };
+}

方案二:禁止拖拽

html
<img src="image.png" ondragstart="return false;" />
<img src="image.png" ondragstart="return false;" />

方案三:使用遮罩层

html
<div style="position: relative; display: inline-block;">
+    <img src="image.png" alt="">
+    <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;
+                background: url(image.png) no-repeat center center / contain; opacity: 0.7;"></div>
+</div>
<div style="position: relative; display: inline-block;">
+    <img src="image.png" alt="">
+    <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;
+                background: url(image.png) no-repeat center center / contain; opacity: 0.7;"></div>
+</div>

方案四:转换为 canvas

js
export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
+  return new Promise((resolve, reject) => {
+    //新建Image对象,引入当前目录下的图片
+    const img = new Image()
+    img.src = url
+    const c = canvas.getContext('2d')!
+
+    //图片初始化完成后调用
+    img.onload = function () {
+      //将canvas的宽高设置为图像的宽高
+      canvas.width = img.width
+      canvas.height = img.height
+
+      //canvas画图片
+      c.drawImage(img, 0, 0, img.width, img.height)
+      resolve()
+    }
+    img.addEventListener('error', (e) => {
+      reject(e)
+    })
+  })
+}
export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
+  return new Promise((resolve, reject) => {
+    //新建Image对象,引入当前目录下的图片
+    const img = new Image()
+    img.src = url
+    const c = canvas.getContext('2d')!
+
+    //图片初始化完成后调用
+    img.onload = function () {
+      //将canvas的宽高设置为图像的宽高
+      canvas.width = img.width
+      canvas.height = img.height
+
+      //canvas画图片
+      c.drawImage(img, 0, 0, img.width, img.height)
+      resolve()
+    }
+    img.addEventListener('error', (e) => {
+      reject(e)
+    })
+  })
+}
js
const throwFn = () => {
+  throw new Error(
+    "Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
+  )
+}
+
+const $canvasRef = useRef<HTMLCanvasElement>(null)
+ useEffect(() => {
+     ;(async () => {
+         await imageToCanvas(props.url, $canvasRef.current!)
+         $canvasRef.current!.toBlob = throwFn
+         $canvasRef.current!.toDataURL = throwFn
+     })()
+ }, [])
+ return (
+     <canvas
+         ref={$canvasRef}
+         onTouchStart={preventDefaultListener}
+         onContextMenu={preventDefaultListener}
+     />
+ )
const throwFn = () => {
+  throw new Error(
+    "Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
+  )
+}
+
+const $canvasRef = useRef<HTMLCanvasElement>(null)
+ useEffect(() => {
+     ;(async () => {
+         await imageToCanvas(props.url, $canvasRef.current!)
+         $canvasRef.current!.toBlob = throwFn
+         $canvasRef.current!.toDataURL = throwFn
+     })()
+ }, [])
+ return (
+     <canvas
+         ref={$canvasRef}
+         onTouchStart={preventDefaultListener}
+         onContextMenu={preventDefaultListener}
+     />
+ )
`,12),e=[o];function t(c,r,y,D,A,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.lean.js" "b/assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.lean.js" new file mode 100644 index 00000000..0ab0dd76 --- /dev/null +++ "b/assets/Interview_JavaScript_\351\253\230\347\272\247\351\235\242\350\257\225\351\242\230.md.0abc2056.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"常见高级面试题","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/JavaScript/高级面试题.md","filePath":"Interview/JavaScript/高级面试题.md"}'),p={name:"Interview/JavaScript/高级面试题.md"},o=l("",12),e=[o];function t(c,r,y,D,A,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.js" "b/assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.js" new file mode 100644 index 00000000..4c08d80f --- /dev/null +++ "b/assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.js" @@ -0,0 +1 @@ +import{_ as a,o as r,c as o,k as e,a as t}from"./chunks/framework.c53372a0.js";const V=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue响应式原理.md","filePath":"Interview/Vue/Vue响应式原理.md"}'),n={name:"Interview/Vue/Vue响应式原理.md"},s=e("h2",{id:"数组劫持原理",tabindex:"-1"},[t("数组劫持原理 "),e("a",{class:"header-anchor",href:"#数组劫持原理","aria-label":'Permalink to "数组劫持原理"'},"​")],-1),c=e("ol",null,[e("li",null,[t("使用 "),e("code",null,"Object.create(Array.prototype)"),t(" 备份原型上的方法")]),e("li",null,"利用 AOP 思想,对 7 个变异方法进行重写,重写函数:先调用原来对应方法,再对新增的每一项进行数据劫持"),e("li")],-1),l=[s,c];function i(_,d,u,p,h,m){return r(),o("div",null,l)}const v=a(n,[["render",i]]);export{V as __pageData,v as default}; diff --git "a/assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.lean.js" "b/assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.lean.js" new file mode 100644 index 00000000..4c08d80f --- /dev/null +++ "b/assets/Interview_Vue_Vue\345\223\215\345\272\224\345\274\217\345\216\237\347\220\206.md.2eeac150.lean.js" @@ -0,0 +1 @@ +import{_ as a,o as r,c as o,k as e,a as t}from"./chunks/framework.c53372a0.js";const V=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue响应式原理.md","filePath":"Interview/Vue/Vue响应式原理.md"}'),n={name:"Interview/Vue/Vue响应式原理.md"},s=e("h2",{id:"数组劫持原理",tabindex:"-1"},[t("数组劫持原理 "),e("a",{class:"header-anchor",href:"#数组劫持原理","aria-label":'Permalink to "数组劫持原理"'},"​")],-1),c=e("ol",null,[e("li",null,[t("使用 "),e("code",null,"Object.create(Array.prototype)"),t(" 备份原型上的方法")]),e("li",null,"利用 AOP 思想,对 7 个变异方法进行重写,重写函数:先调用原来对应方法,再对新增的每一项进行数据劫持"),e("li")],-1),l=[s,c];function i(_,d,u,p,h,m){return r(),o("div",null,l)}const v=a(n,[["render",i]]);export{V as __pageData,v as default}; diff --git "a/assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.js" "b/assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.js" new file mode 100644 index 00000000..ec49a5ac --- /dev/null +++ "b/assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as a,Q as o}from"./chunks/framework.c53372a0.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue基础篇.md","filePath":"Interview/Vue/Vue基础篇.md"}'),r={name:"Interview/Vue/Vue基础篇.md"},n=o('

对MVVM的理解

MVVM 由 MVC 模型演变而来,M(Model)代表数据模型,V(View)代表用户操作的界面,VM(ViewModel)代表业务逻辑层,

充当数据模型与视图界面的桥梁,可以把数据绑定到页面,页面操作触发数据更新,数据修改自动触发视图更新。

Mixins的原理

Vue 的 mixins混入 可以抽离封装Vue 组件选项达到复用的效果。

data、provide:后者的值将对前者的值进行扩展,相同属性名(非对象)则以后者的属性值为准,如果两者的值是对象,但值不相等,则继续进行合并,

生命周期钩子函数:将后者的生命周期钩子函数拼接到前者的生命周期钩子函数,调用时依次执行;

components、filters、directives:对前者的属性进行拷贝扩展,属性相同则后者覆盖前者;

**watch:**与生命周期钩子函数类似,将后者的 watch拼接到前者的 watch后面;

props、methods、inject、computed:定义一个对象 ret,遍历前者的属性或方法,对 ret进行扩展,再遍历后者的属性或方法,后者将覆盖前者的属性或方法;

默认策略:策略中没有定义的策略,后者有则返回后者,否则返回前者;

',11),s=[n];function i(p,c,_,d,V,m){return t(),a("div",null,s)}const u=e(r,[["render",i]]);export{l as __pageData,u as default}; diff --git "a/assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.lean.js" "b/assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.lean.js" new file mode 100644 index 00000000..0bf24b22 --- /dev/null +++ "b/assets/Interview_Vue_Vue\345\237\272\347\241\200\347\257\207.md.d7fd744f.lean.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as a,Q as o}from"./chunks/framework.c53372a0.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue基础篇.md","filePath":"Interview/Vue/Vue基础篇.md"}'),r={name:"Interview/Vue/Vue基础篇.md"},n=o("",11),s=[n];function i(p,c,_,d,V,m){return t(),a("div",null,s)}const u=e(r,[["render",i]]);export{l as __pageData,u as default}; diff --git "a/assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.js" "b/assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.js" new file mode 100644 index 00000000..c1d4e15e --- /dev/null +++ "b/assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.js" @@ -0,0 +1,59 @@ +import{_ as s,o as a,c as n,Q as e}from"./chunks/framework.c53372a0.js";const u=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue声明周期.md","filePath":"Interview/Vue/Vue声明周期.md"}'),l={name:"Interview/Vue/Vue声明周期.md"},p=e(`

Vue声明周期

js
//自带 8 个
+beforeCreate
+created
+beforeMount
+mounted
+beforeUpdate
+updated
+beforeDestory
+destoryed
//自带 8 个
+beforeCreate
+created
+beforeMount
+mounted
+beforeUpdate
+updated
+beforeDestory
+destoryed

嵌套组件组件执行顺序

js
//父组件
+beforeCreate
+created
+beforeMount
+  //子组件
+  beforeCreate
+  created
+  beforeMount
+  mounted
+    //孙子组件
+      beforeCreate
+      created
+      beforeMount
+      mounted
//父组件
+beforeCreate
+created
+beforeMount
+  //子组件
+  beforeCreate
+  created
+  beforeMount
+  mounted
+    //孙子组件
+      beforeCreate
+      created
+      beforeMount
+      mounted

beforeCreate 与 created 区别

created 与 mounted 区别

请求问题:当需要子组件的请求需要比父组件完成时,可以把父组件请求卸载mounted中,子组件写在created中。

keep-alive内置缓存组件

额外增加两个声明周期:activated, deactivated

js
//第一次执行顺序
+  beforeCreate
+  created
+  beforeMount
+  mounted
+  activated
+
+  //第二次:多次进入详情页,在activated钩子中,判断 id 相同则不需要发请求
+  activated
//第一次执行顺序
+  beforeCreate
+  created
+  beforeMount
+  mounted
+  activated
+
+  //第二次:多次进入详情页,在activated钩子中,判断 id 相同则不需要发请求
+  activated

虚拟 DOM(VNode) 和 DOM

  1. VNode是一个纯 JavaScript 对象,用来描述真实 DOM 中的一个节点,属性比真实 dom 精简许多。

虚拟 DOM 的优点包括:

性能优化:由于真实 DOM 操作非常耗费性能,而虚拟 DOM 可以在内存中进行操作,然后再一次性渲染到真实 DOM 上,从而减少了不必要的 DOM 操作,提高了性能。

跨平台:虚拟 DOM 可以轻松地支持多种平台,比如浏览器、移动端、服务器端等。

组件化开发:Vue 的组件是以 VNode 为基础的,通过对 VNode 的操作,可以方便地实现组件的开发。

Vue3.0性能提升

  1. 响应式系统不需要深度遍历就可以对整个对象监听
  2. 在diff算法中增加了静态标记
  3. 源码体积减小,所有 API 都可以按需引入
`,18),o=[p];function t(c,r,i,d,D,y){return a(),n("div",null,o)}const B=s(l,[["render",t]]);export{u as __pageData,B as default}; diff --git "a/assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.lean.js" "b/assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.lean.js" new file mode 100644 index 00000000..0aa14ddc --- /dev/null +++ "b/assets/Interview_Vue_Vue\345\243\260\346\230\216\345\221\250\346\234\237.md.4220f397.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as e}from"./chunks/framework.c53372a0.js";const u=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue声明周期.md","filePath":"Interview/Vue/Vue声明周期.md"}'),l={name:"Interview/Vue/Vue声明周期.md"},p=e("",18),o=[p];function t(c,r,i,d,D,y){return a(),n("div",null,o)}const B=s(l,[["render",t]]);export{u as __pageData,B as default}; diff --git "a/assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.js" "b/assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.js" new file mode 100644 index 00000000..07268db7 --- /dev/null +++ "b/assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as r}from"./chunks/framework.c53372a0.js";const d=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue进阶篇.md","filePath":"Interview/Vue/Vue进阶篇.md"}'),a={name:"Interview/Vue/Vue进阶篇.md"};function n(o,s,c,_,i,p){return t(),r("div")}const m=e(a,[["render",n]]);export{d as __pageData,m as default}; diff --git "a/assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.lean.js" "b/assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.lean.js" new file mode 100644 index 00000000..07268db7 --- /dev/null +++ "b/assets/Interview_Vue_Vue\350\277\233\351\230\266\347\257\207.md.786b9622.lean.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as r}from"./chunks/framework.c53372a0.js";const d=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/Vue进阶篇.md","filePath":"Interview/Vue/Vue进阶篇.md"}'),a={name:"Interview/Vue/Vue进阶篇.md"};function n(o,s,c,_,i,p){return t(),r("div")}const m=e(a,[["render",n]]);export{d as __pageData,m as default}; diff --git "a/assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.js" "b/assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.js" new file mode 100644 index 00000000..b20c8c8d --- /dev/null +++ "b/assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.js" @@ -0,0 +1 @@ +import{_ as e,o,c as i,Q as c}from"./chunks/framework.c53372a0.js";const m=JSON.parse('{"title":"npm run xxx执行过程","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/npm run xxx执行过程.md","filePath":"Interview/Vue/npm run xxx执行过程.md"}'),n={name:"Interview/Vue/npm run xxx执行过程.md"},d=c('

npm run xxx执行过程

vue cli 项目

  1. npm run 会先把 node_modules/.bin 加入到 PATH 环境变量

  2. 找到项目根目录 package.json 文件中 scripts 对应的脚本并执行对应命令

  3. 相当于执行 vue-cli-service serve ,并去找到npm i (npm i @vue/cli-service)所生成的软连接 ./bin/vue-cli-service

  4. 接着去执行软连接指向的 node_modules/@vue/cli-service/bin/vue-cli-service.js (package-lock.json记录了映射关系)

    1. vue-cli-service.js主要解析和比对 node 版本,不匹配则报错
    2. 获取和解析命令行参数,启动服务执行命令

vite项目

  1. npm run 会先把 node_modules/.bin 加入到 PATH 环境变量
  2. 找到项目根目录 package.json 文件中 scripts 对应的脚本并执行对应命令
  3. 去找.bin/vite 软链接,进而找到 node_modules/.pnpm/vite@4.1.1/node_modules/vite/bin/vite.js执行
',5),l=[d];function a(r,t,s,u,p,_){return o(),i("div",null,l)}const v=e(n,[["render",a]]);export{m as __pageData,v as default}; diff --git "a/assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.lean.js" "b/assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.lean.js" new file mode 100644 index 00000000..af427d03 --- /dev/null +++ "b/assets/Interview_Vue_npm run xxx\346\211\247\350\241\214\350\277\207\347\250\213.md.9da37746.lean.js" @@ -0,0 +1 @@ +import{_ as e,o,c as i,Q as c}from"./chunks/framework.c53372a0.js";const m=JSON.parse('{"title":"npm run xxx执行过程","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/npm run xxx执行过程.md","filePath":"Interview/Vue/npm run xxx执行过程.md"}'),n={name:"Interview/Vue/npm run xxx执行过程.md"},d=c("",5),l=[d];function a(r,t,s,u,p,_){return o(),i("div",null,l)}const v=e(n,[["render",a]]);export{m as __pageData,v as default}; diff --git "a/assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.js" "b/assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.js" new file mode 100644 index 00000000..2f6c6079 --- /dev/null +++ "b/assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.js" @@ -0,0 +1,87 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"前端项目优化","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/前端项目优化.md","filePath":"Interview/Vue/前端项目优化.md"}'),p={name:"Interview/Vue/前端项目优化.md"},o=l(`

前端项目优化

HTML

CSS

JavaScript

构建优化

移除console

npm install babel-plugin-transform-remove-console --D

js
//babel.config.js
+const proPlugins = [];
+if (process.env.NODE_ENV === 'production') {
+  proPlugins.push('transform-remove-console');
+}
+module.exports = {
+  plugins: [
+      ...proPlugins
+  ]
+};
//babel.config.js
+const proPlugins = [];
+if (process.env.NODE_ENV === 'production') {
+  proPlugins.push('transform-remove-console');
+}
+module.exports = {
+  plugins: [
+      ...proPlugins
+  ]
+};

分包和共享依赖

js
 configureWebpack: {
+    resolve: {
+      alias: {
+        "@": resolve("src"),
+      },
+    },
+    optimization: {
+      runtimeChunk: "single",
+      splitChunks: {
+        chunks: "all",
+        maxInitialRequests: Infinity,
+        minSize: 20000,
+        cacheGroups: {
+          common: {
+            name: "common",
+            chunks: "all",
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2,
+          },
+          vendor: {
+            test: /[\\\\/]node_modules[\\\\/]/,
+            chunks: "initial", //从入口文件抽离
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2, //只要使用2次以上就抽离
+            name(module) {
+              const packageName = module.context.match(
+                /[\\\\/]node_modules[\\\\/](.*?)([\\\\/]|$)/
+              )[1];
+              return \`npm.\${packageName.replace("@", "")}\`;
+            },
+          },
+        },
+      },
+    },
+  },
 configureWebpack: {
+    resolve: {
+      alias: {
+        "@": resolve("src"),
+      },
+    },
+    optimization: {
+      runtimeChunk: "single",
+      splitChunks: {
+        chunks: "all",
+        maxInitialRequests: Infinity,
+        minSize: 20000,
+        cacheGroups: {
+          common: {
+            name: "common",
+            chunks: "all",
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2,
+          },
+          vendor: {
+            test: /[\\\\/]node_modules[\\\\/]/,
+            chunks: "initial", //从入口文件抽离
+            minSize: 0, //只要大于0字节就抽离
+            minChunks: 2, //只要使用2次以上就抽离
+            name(module) {
+              const packageName = module.context.match(
+                /[\\\\/]node_modules[\\\\/](.*?)([\\\\/]|$)/
+              )[1];
+              return \`npm.\${packageName.replace("@", "")}\`;
+            },
+          },
+        },
+      },
+    },
+  },
`,10),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{B as __pageData,C as default}; diff --git "a/assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.lean.js" "b/assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.lean.js" new file mode 100644 index 00000000..c7948926 --- /dev/null +++ "b/assets/Interview_Vue_\345\211\215\347\253\257\351\241\271\347\233\256\344\274\230\345\214\226.md.3cd67a0e.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"前端项目优化","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/前端项目优化.md","filePath":"Interview/Vue/前端项目优化.md"}'),p={name:"Interview/Vue/前端项目优化.md"},o=l("",10),e=[o];function c(t,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",c]]);export{B as __pageData,C as default}; diff --git "a/assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.js" "b/assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.js" new file mode 100644 index 00000000..c9cb4bae --- /dev/null +++ "b/assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.js" @@ -0,0 +1,35 @@ +import{_ as s,o as a,c as n,Q as p}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/常见Path区别.md","filePath":"Interview/Vue/常见Path区别.md"}'),l={name:"Interview/Vue/常见Path区别.md"},o=p(`

VueRouter的 base

VueRouter的base属性是指应用的基路径,它会影响到所有使用了vue-router的路由路径,包括 routes 配置中的路径和 通过 $router.push() 或 $router.replace() 调用的路径。

在router对象中,base属性可以通过以下方式设置:

javascript
const router = new VueRouter({
+  base: '/my-app/'
+})
const router = new VueRouter({
+  base: '/my-app/'
+})

这个属性值的默认值为 '/'。如果你的应用被部署在一个子目录下,你就需要手动指定base属性的值。

例如,假设你的应用被部署在http://example.com/my-app/这个路径下,那么你就需要设置如下的base属性:

javascript
const router = new VueRouter({
+  base: '/my-app/'
+})
const router = new VueRouter({
+  base: '/my-app/'
+})

这个设置是非常重要的,因为Vue Router 路由器的默认行为是从根路径(localhost:8080/) 开始的,

如果你需要从你的实际路径下查看(例如 localhost:8080/my-project/),就需要设置base属性了。

除了上述的情况之外,一般我们都不会配置base属性,这个属性的作用主要是为了适应应用被部署在服务器上的子目录下的情况。

vue.config.js的 publicPath

在 Vue.js 中, publicPath 是用来指定应用程序部署的基础 URL。它作用于构建过程中的静态文件的路径,

同时也影响 Vue Router 中 router-link 组件的路径。一般来说,我们在开发环境和生产环境使用不同的 publicPath 值,来确保应用在不同环境下都能够正确访问静态文件。

以下是一些常见的 publicPath 配置:

  • "/":将生成的静态文件放在根目录下,这是默认值。
  • "./":将生成的静态文件放在当前目录下。
  • "../":将生成的静态文件放在上级目录下。

在 vue.config.js 中,我们可以通过设置 publicPath 来配置应用的部署路径。例如,我们可以将 publicPath 设置为 "/my-app/",

则构建出的静态文件实际上会被部署到类似于 http://example.com/my-app/ 这样的路径下。代码示例:

javascript
module.exports = {
+  publicPath: process.env.NODE_ENV === 'production'
+    ? '/my-app/'
+    : '/'
+}
module.exports = {
+  publicPath: process.env.NODE_ENV === 'production'
+    ? '/my-app/'
+    : '/'
+}

通常可以在根目录配置环境变量,相对于不同环境打包时的打包命令

json
//package.json
+"scripts": {
+    "serve": "vue-cli-service serve --open --port 9999",
+    "build:server": "vue-cli-service build ",
+    "build:local": "vue-cli-service build --mode buildlocal"
+  },
//package.json
+"scripts": {
+    "serve": "vue-cli-service serve --open --port 9999",
+    "build:server": "vue-cli-service build ",
+    "build:local": "vue-cli-service build --mode buildlocal"
+  },
js
//.env.production   --服务器打包预览环境变量
+OUTPUT_DIR=/opt/nginx/www/html/music
+BASE_URL=/music/
//.env.production   --服务器打包预览环境变量
+OUTPUT_DIR=/opt/nginx/www/html/music
+BASE_URL=/music/
js
//.env.buildlocal   --本地打包预览环境变量
+OUTPUT_DIR=dist
+BASE_URL=/
//.env.buildlocal   --本地打包预览环境变量
+OUTPUT_DIR=dist
+BASE_URL=/
`,22),e=[o];function t(c,r,y,i,A,u){return a(),n("div",null,e)}const d=s(l,[["render",t]]);export{B as __pageData,d as default}; diff --git "a/assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.lean.js" "b/assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.lean.js" new file mode 100644 index 00000000..4927c4e8 --- /dev/null +++ "b/assets/Interview_Vue_\345\270\270\350\247\201Path\345\214\272\345\210\253.md.56f4fc59.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as p}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/常见Path区别.md","filePath":"Interview/Vue/常见Path区别.md"}'),l={name:"Interview/Vue/常见Path区别.md"},o=p("",22),e=[o];function t(c,r,y,i,A,u){return a(),n("div",null,e)}const d=s(l,[["render",t]]);export{B as __pageData,d as default}; diff --git "a/assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.js" "b/assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.js" new file mode 100644 index 00000000..6ab1051d --- /dev/null +++ "b/assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.js" @@ -0,0 +1,97 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/自定义指令.md","filePath":"Interview/Vue/自定义指令.md"}'),p={name:"Interview/Vue/自定义指令.md"},o=l(`

一键复制

js
//方案一:
+Vue.directive('copy', {
+  bind: function (el) {
+    el.addEventListener('click', function () {
+      var range = document.createRange();
+      range.selectNode(el);
+      window.getSelection().addRange(range);
+      document.execCommand('copy');
+      window.getSelection().removeAllRanges();
+    });
+  }
+});
+
+//方案二:
+import { Notification } from "element-ui";
+export const COPY = {
+  bind(el, { value }) {
+    el.$value = value;
+    el.handler = () => {
+      if (!el.$value) {
+        Notification.success({
+          title: "无复制内容",
+        });
+        return;
+      }
+      const textarea = document.createElement("textarea");
+      textarea.readOnly = "readonly";
+      textarea.style.position = "absolute";
+      textarea.style.left = "-9999px";
+      textarea.value = el.$value;
+      document.body.appendChild(textarea);
+      textarea.select();
+      const result = document.execCommand("Copy");
+      if (result) {
+        Notification.success({
+          title: "复制成功",
+        });
+      }
+      document.body.removeChild(textarea);
+    };
+    el.addEventListener("click", el.handler);
+  },
+  componentUpdated(el, { value }) {
+    el.$value = value;
+  },
+  unbind(el) {
+    el.removeEventListener("click", el.handler);
+  },
+};
//方案一:
+Vue.directive('copy', {
+  bind: function (el) {
+    el.addEventListener('click', function () {
+      var range = document.createRange();
+      range.selectNode(el);
+      window.getSelection().addRange(range);
+      document.execCommand('copy');
+      window.getSelection().removeAllRanges();
+    });
+  }
+});
+
+//方案二:
+import { Notification } from "element-ui";
+export const COPY = {
+  bind(el, { value }) {
+    el.$value = value;
+    el.handler = () => {
+      if (!el.$value) {
+        Notification.success({
+          title: "无复制内容",
+        });
+        return;
+      }
+      const textarea = document.createElement("textarea");
+      textarea.readOnly = "readonly";
+      textarea.style.position = "absolute";
+      textarea.style.left = "-9999px";
+      textarea.value = el.$value;
+      document.body.appendChild(textarea);
+      textarea.select();
+      const result = document.execCommand("Copy");
+      if (result) {
+        Notification.success({
+          title: "复制成功",
+        });
+      }
+      document.body.removeChild(textarea);
+    };
+    el.addEventListener("click", el.handler);
+  },
+  componentUpdated(el, { value }) {
+    el.$value = value;
+  },
+  unbind(el) {
+    el.removeEventListener("click", el.handler);
+  },
+};
`,2),e=[o];function t(c,r,y,D,A,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{i as __pageData,C as default}; diff --git "a/assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.lean.js" "b/assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.lean.js" new file mode 100644 index 00000000..a8c84859 --- /dev/null +++ "b/assets/Interview_Vue_\350\207\252\345\256\232\344\271\211\346\214\207\344\273\244.md.3d2ea0a9.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const i=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/Vue/自定义指令.md","filePath":"Interview/Vue/自定义指令.md"}'),p={name:"Interview/Vue/自定义指令.md"},o=l("",2),e=[o];function t(c,r,y,D,A,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{i as __pageData,C as default}; diff --git a/assets/Interview_index.md.ff0a75dc.js b/assets/Interview_index.md.ff0a75dc.js new file mode 100644 index 00000000..d8262afb --- /dev/null +++ b/assets/Interview_index.md.ff0a75dc.js @@ -0,0 +1 @@ +import{_ as t,o as a,c as s,k as e,a as o}from"./chunks/framework.c53372a0.js";const u=JSON.parse('{"title":"面试","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/index.md","filePath":"Interview/index.md"}'),n={name:"Interview/index.md"},c=e("h1",{id:"面试",tabindex:"-1"},[o("面试 "),e("a",{class:"header-anchor",href:"#面试","aria-label":'Permalink to "面试"'},"​")],-1),r=e("div",{class:"tip custom-block"},[e("p",{class:"custom-block-title"},"TIP"),e("p",null,"面试题总结与归纳!")],-1),i=[c,r];function d(l,_,p,m,h,f){return a(),s("div",null,i)}const k=t(n,[["render",d]]);export{u as __pageData,k as default}; diff --git a/assets/Interview_index.md.ff0a75dc.lean.js b/assets/Interview_index.md.ff0a75dc.lean.js new file mode 100644 index 00000000..d8262afb --- /dev/null +++ b/assets/Interview_index.md.ff0a75dc.lean.js @@ -0,0 +1 @@ +import{_ as t,o as a,c as s,k as e,a as o}from"./chunks/framework.c53372a0.js";const u=JSON.parse('{"title":"面试","description":"","frontmatter":{},"headers":[],"relativePath":"Interview/index.md","filePath":"Interview/index.md"}'),n={name:"Interview/index.md"},c=e("h1",{id:"面试",tabindex:"-1"},[o("面试 "),e("a",{class:"header-anchor",href:"#面试","aria-label":'Permalink to "面试"'},"​")],-1),r=e("div",{class:"tip custom-block"},[e("p",{class:"custom-block-title"},"TIP"),e("p",null,"面试题总结与归纳!")],-1),i=[c,r];function d(l,_,p,m,h,f){return a(),s("div",null,i)}const k=t(n,[["render",d]]);export{u as __pageData,k as default}; diff --git "a/assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.js" "b/assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.js" new file mode 100644 index 00000000..6fa3792e --- /dev/null +++ "b/assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.js" @@ -0,0 +1,1181 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"网络拓扑图代码","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Graphical/Antv代码片段集锦.md","filePath":"Problem/Graphical/Antv代码片段集锦.md"}'),p={name:"Problem/Graphical/Antv代码片段集锦.md"},o=l(`

网络拓扑图代码

图实例化

js
import { commonRegister ,viewRegister} './registerElements.js'
+
+//1.初始化实例
+initChart() {
+  let halfWidth = this.width / 2;
+  let halfHeight = this.height / 2;
+  if (!this.graph) {
+    commonRegister()
+    viewRegister()
+    const toolbar = new G6.ToolBar({
+      position: { x: 10, y: 10 },
+      getContent: () => {
+         const outDiv = document.createElement('div');
+          let style = 'cursor: pointer;vertical-align: middle;line-height:24px;font-size:18px;'
+          outDiv.innerHTML = \`<ul>
+              <li code='zoomOut' style="${style}" class="iconfont icon-fangda" title="放大"></li>
+              <li code='zoomIn'  style="\${style}" class="iconfont icon-suoxiao" title="缩小"></li>
+              <li code='autoZoom' style="\${style}" class="iconfont icon-fitscreen24" title="居中"></li>
+            </ul>\`
+          return outDiv
+      },
+     handleClick: (code) => {
+          if (code === 'zoomOut') {
+             toolbar.zoomOut()
+          } else if (code === 'zoomIn') {
+             toolbar.zoomIn()
+          }else if(code === 'autoZoom'){
+             toolbar.autoZoom()
+          }
+        }
+    });
+    this.graph = new G6.Graph({
+      container: "topoChart",
+      width: this.width,
+      height: this.height,
+      fitView: true,
+      fitViewPadding: 100,
+      groupByTypes: false,
+      linkCenter: false,
+      layout: {
+        pipes: [
+          {
+            // 该子图所使用的布局类型
+            type: "circular",
+            center: [halfWidth, halfHeight],
+            radius: 80,
+            nodesFilter: (node) => node.sysType === "vpe",
+          },
+        ],
+      },
+      //交互行为相关配置
+      modes: {
+        default: ["drag-canvas", "zoom-canvas", {type: "drag-combo", shouldEnd(e, parent) {
+          if(parent) {
+            return false;
+          }
+          return true;
+        }}],
+      },
+      plugins: [toolbar],
+      defaultNode: {
+        type: "bubble",
+        labelCfg: {
+          position: "center",
+          style: {
+            fill: "white",
+            stroke: "#fff",
+          },
+        },
+      },
+      defaultEdge: {
+        color: "#888",
+        type: "animate-line",
+      },
+      defaultCombo: {
+        padding: 1,
+        style: {
+          cursor: "all-scroll",
+        },
+        labelCfg: {
+          style: {
+            opacity: 0,
+            fill: "#303133",
+            fontSize: 12,
+            stroke: "#fff",
+          },
+        },
+      },
+    });
+    //监听事件
+     this.graphBehaviors();
+  }
+},
+graphBehaviors(){
+    this.graph.on('node:click',this.debounce(this.eventHandle, 300));
+ //this.graph.on('edge:click'... 
+},
+debounce(fn, delay) {
+  const delays = delay || 300;
+  let timer;
+  return function() {
+    const th = this;
+    const args = arguments;
+    if (timer) {
+      clearTimeout(timer);
+    }
+    timer = setTimeout(function() {
+      timer = null;
+      fn.apply(th, args);
+    }, delays);
+  };
+},
+    //2.查询数据
+queryChartData(){
+    //处理数据
+    this.dealData(data)
+}
+//3.处理数据
+dealData(data ) {
+    //VPE节点
+    nodes =  ...
+    edges = ...
+    combos = ...
+    this.drawChart(...);
+}
+//4.渲染数据
+drawChart() {
+  this.graph.read({
+    nodes,
+    edges,
+    combos,
+  });
+},
import { commonRegister ,viewRegister} './registerElements.js'
+
+//1.初始化实例
+initChart() {
+  let halfWidth = this.width / 2;
+  let halfHeight = this.height / 2;
+  if (!this.graph) {
+    commonRegister()
+    viewRegister()
+    const toolbar = new G6.ToolBar({
+      position: { x: 10, y: 10 },
+      getContent: () => {
+         const outDiv = document.createElement('div');
+          let style = 'cursor: pointer;vertical-align: middle;line-height:24px;font-size:18px;'
+          outDiv.innerHTML = \`<ul>
+              <li code='zoomOut' style="${style}" class="iconfont icon-fangda" title="放大"></li>
+              <li code='zoomIn'  style="\${style}" class="iconfont icon-suoxiao" title="缩小"></li>
+              <li code='autoZoom' style="\${style}" class="iconfont icon-fitscreen24" title="居中"></li>
+            </ul>\`
+          return outDiv
+      },
+     handleClick: (code) => {
+          if (code === 'zoomOut') {
+             toolbar.zoomOut()
+          } else if (code === 'zoomIn') {
+             toolbar.zoomIn()
+          }else if(code === 'autoZoom'){
+             toolbar.autoZoom()
+          }
+        }
+    });
+    this.graph = new G6.Graph({
+      container: "topoChart",
+      width: this.width,
+      height: this.height,
+      fitView: true,
+      fitViewPadding: 100,
+      groupByTypes: false,
+      linkCenter: false,
+      layout: {
+        pipes: [
+          {
+            // 该子图所使用的布局类型
+            type: "circular",
+            center: [halfWidth, halfHeight],
+            radius: 80,
+            nodesFilter: (node) => node.sysType === "vpe",
+          },
+        ],
+      },
+      //交互行为相关配置
+      modes: {
+        default: ["drag-canvas", "zoom-canvas", {type: "drag-combo", shouldEnd(e, parent) {
+          if(parent) {
+            return false;
+          }
+          return true;
+        }}],
+      },
+      plugins: [toolbar],
+      defaultNode: {
+        type: "bubble",
+        labelCfg: {
+          position: "center",
+          style: {
+            fill: "white",
+            stroke: "#fff",
+          },
+        },
+      },
+      defaultEdge: {
+        color: "#888",
+        type: "animate-line",
+      },
+      defaultCombo: {
+        padding: 1,
+        style: {
+          cursor: "all-scroll",
+        },
+        labelCfg: {
+          style: {
+            opacity: 0,
+            fill: "#303133",
+            fontSize: 12,
+            stroke: "#fff",
+          },
+        },
+      },
+    });
+    //监听事件
+     this.graphBehaviors();
+  }
+},
+graphBehaviors(){
+    this.graph.on('node:click',this.debounce(this.eventHandle, 300));
+ //this.graph.on('edge:click'... 
+},
+debounce(fn, delay) {
+  const delays = delay || 300;
+  let timer;
+  return function() {
+    const th = this;
+    const args = arguments;
+    if (timer) {
+      clearTimeout(timer);
+    }
+    timer = setTimeout(function() {
+      timer = null;
+      fn.apply(th, args);
+    }, delays);
+  };
+},
+    //2.查询数据
+queryChartData(){
+    //处理数据
+    this.dealData(data)
+}
+//3.处理数据
+dealData(data ) {
+    //VPE节点
+    nodes =  ...
+    edges = ...
+    combos = ...
+    this.drawChart(...);
+}
+//4.渲染数据
+drawChart() {
+  this.graph.read({
+    nodes,
+    edges,
+    combos,
+  });
+},
js
mounted() {
+    this.chartLoading = true
+    this.width = document.getElementById("topoChart").scrollWidth;
+    this.height = document.getElementById("topoChart").scrollHeight || 600;
+    this.initChart();
+    this.queryChartData();
+    this.chartLoading = false
+    //监听窗口大小变化,重绘网络拓扑
+    window.addEventListener('resize',this.rePaint )
+  },
+beforeDestroy() {
+    if (this.graph) {
+      this.graph.clear();
+      this.graph.destroy();
+    }
+    this.data = Object.assign(this.$data, this.$options.data());
+},
mounted() {
+    this.chartLoading = true
+    this.width = document.getElementById("topoChart").scrollWidth;
+    this.height = document.getElementById("topoChart").scrollHeight || 600;
+    this.initChart();
+    this.queryChartData();
+    this.chartLoading = false
+    //监听窗口大小变化,重绘网络拓扑
+    window.addEventListener('resize',this.rePaint )
+  },
+beforeDestroy() {
+    if (this.graph) {
+      this.graph.clear();
+      this.graph.destroy();
+    }
+    this.data = Object.assign(this.$data, this.$options.data());
+},

注册节点

js
//registerElements.js
+import G6 from "@antv/g6";
+//共同节点注册
+export  function commonRegister(){
+  // 注册实线动画
+  G6.registerEdge("animate-line",
+    {
+      drawShape(cfg, group) {
+        const self = this;
+        let shapeStyle = self.getShapeStyle(cfg);
+        shapeStyle = Object.assign(shapeStyle, {
+          opacity: 0,
+          strokeOpacity: 0,
+        });
+        const keyShape = group.addShape("path", {
+          attrs: shapeStyle,
+          name: "path-shape",
+        });
+        return keyShape;
+      },
+      afterDraw(cfg, group) {
+        const shape = group.get("children")[0];
+        //线条动画
+        shape.animate(
+          (ratio) => {
+            const opacity = ratio * cfg.style.opacity;
+            const strokeOpacity = ratio * cfg.style.strokeOpacity;
+            return {
+              opacity: ratio || opacity,
+              strokeOpacity: ratio || strokeOpacity,
+            };
+          },
+          {
+            duration: 300,
+          }
+        );
+        //箭头动画
+        const startPoint = shape.getPoint(0);
+        const circle = group.addShape("circle", {
+          attrs: {
+            x: startPoint.x,
+            y: startPoint.y,
+            fill: "#1890ff",
+            r: 2,
+          },
+          name: "circle-shape",
+        });
+        circle.animate(
+          (ratio) => {
+            const tmpPoint = shape.getPoint(ratio);
+            return {
+              x: tmpPoint.x,
+              y: tmpPoint.y,
+            };
+          },
+          {
+            repeat: true,
+            duration: 3000,
+          }
+        );
+      },
+      setState(name, value, item) {
+        const shape = item.get("keyShape");
+        if (name === "disappearing" && value) {
+          shape.animate(
+            (ratio) => {
+              return {
+                opacity: 1 - ratio,
+                strokeOpacity: 1 - ratio,
+              };
+            },
+            {
+              duration: 200,
+            }
+          );
+        } else if (name === "dark") {
+          if (value) shape.attr("opacity", 0.2);
+          else shape.attr("opacity", 1);
+        }
+      },
+    },
+    "line"
+  );
+  //注册iconfont节点
+  G6.registerNode("iconfontHub", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle ,size } = cfg;
+      group.addShape("circle", {
+        attrs: {
+          x: 0,
+          y: size / 2,
+          r: size,
+        },
+        name: "hub-bg-shape",
+      });
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: size  / 2,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          text: cfg.text,
+          fontSize: Math.round(size),
+          ...style,
+        },
+        name: "hub-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: Math.round(size/4),
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "hub-label",
+      });
+      return keyShape;
+    },
+    // afterDraw(cfg, group) {
+    //   const shape = group.get('children')[0];
+    //   shape.animate(
+    //     (ratio) => {
+    //       let fill = '#C396ED'
+    //       if(ratio > 0.6){
+    //         fill = '#FFCF8B'
+    //       }else if(ratio > 0.3){
+    //         fill = '#C396ED'
+    //       }else {
+    //         fill = '#75D882'
+    //       }
+    //       return {
+    //         fill,
+    //       };
+    //     },
+    //     {
+    //       repeat: true,
+    //       duration: 1500,
+    //       // easing: 'easeCubic',
+    //     },
+    //   );
+    // },
+  });
+  //自定义节点和节点动画
+  G6.registerNode( "vpe-rect-animate",
+    {
+    afterDraw(cfg, group) {
+      const { width, height, stroke, radius } = this.getShapeStyle(cfg);
+      const x = -width / 2,
+        y = -height / 2;
+      const back1 = group.addShape("rect", {
+        zIndex: -3,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback1-shape",
+      });
+      const back2 = group.addShape("rect", {
+        zIndex: -2,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback2-shape",
+      });
+      const back3 = group.addShape("circle", {
+        zIndex: -1,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback3-shape",
+      });
+      group.sort(); // Sort according to the zIndex
+      back1.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: -300,
+          repeat: true, // repeat
+        }
+      ); // no delay
+      back2.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 1000,
+          repeat: true,  
+        }
+      );  
+      back3.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 2000,
+          repeat: true, // repeat
+        }
+      ); // 3s delay
+    },
+  },
+  "rect"
+);
+}
+//弹窗特有节点注册
+export function dialogRegister(){
+   //注册iconfont节点
+   G6.registerNode("iconfontCpe", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle } = cfg;
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 0,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.text,
+          fontSize: cfg.size,
+          ...style,
+        },
+        name: "cpe-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 10,
+          textAlign: "center",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "cpe-label",
+      });
+  
+      return keyShape;
+    },
+    afterDraw(cfg, group) {
+      const shape = group.get('children')[0];
+      shape.animate(
+        (ratio) => {
+          let text = '\\ue604'
+          if(ratio > 0.6){
+            text = '\\ue604'
+          }else if(ratio > 0.3){
+            text = '\\ue606'
+          }else {
+            text = '\\ue605'
+          }
+          return {
+            text,
+          };
+        },
+        {
+          repeat: true,
+          duration: 1500,
+          delay: 3000,
+          // easing: 'easeCubic',
+        },
+      );
+    },
+  });
+  //注册虚线动画
+  // G6.registerEdge("vpn-line-dash",
+  //   {
+  //     afterDraw(cfg, group) {
+  //       const shape = group.get("children")[0];
+  //       let index = 0;
+  //       shape.animate(
+  //         () => {
+  //           index = index+0.2;
+  //           if (index > 9) {
+  //             index = 0;
+  //           }
+  //           const res = {
+  //             lineDash: [4, 4],
+  //             lineDashOffset: -index,
+  //           };
+  //           return res;
+  //         },
+  //         {
+  //           repeat: true,
+  //           duration:10000,
+  //         }
+  //       );
+  //     },
+  //   },
+  //   "line"
+  // );
+}
+
+//网络拓扑总览特有节点注册
+export function viewRegister(){
+  //注册iconfont combos
+  // G6.registerCombo("cloudCombo",
+  //   {
+  //     drawShape: function drawShape(cfg, group) {
+  //       // const {  labelCfg: labelStyle   } = cfg;
+  //       const keyShape = group.addShape("text", { 
+  //         attrs: {
+  //           y: 0,
+  //           x: 0,
+  //           fill: cfg.style.fill,
+  //           stroke: cfg.style.fill,
+  //           fontFamily: "iconfont",
+  //           textAlign: "center",
+  //           textBaseline: "middle",
+  //           text: "\\ue603",
+  //           fontSize: 320,
+  //           zIndex: 8,
+  //         },
+  //         name: "cloud",
+  //       });
+  //           //添加label
+  //     // group.addShape("text", {
+  //     //   attrs: {
+  //     //     x: 0,
+  //     //     y: -80,
+  //     //     textAlign: "center",
+  //     //     textBaseline: "middle",
+  //     //     text: cfg.label,
+  //     //     ...labelStyle.style,
+  //     //   },
+  //     //   name: "hubCombo-label",
+  //     // });
+  //       return keyShape;
+  //     },
+  //   },
+  //   "cicle"
+  // );
+    //注册SVG combo
+  G6.registerCombo(
+      "cloudCombo",
+      {
+        drawShape: function drawShape(cfg, group) {
+          const { labelCfg  } = cfg;
+          let str = 'M 448 102.875 c 0 -82.09 -56.678 -150.9 -132.996 -169.48 C 311.762 -195.305 206.546 -298.667 77.142 -298.667 c -75.792 0 -143.266 35.494 -186.854 90.732 c -24.442 -31.598 -62.69 -51.96 -105.708 -51.96 c -73.81 0 -133.642 59.874 -133.642 133.722 c 0 6.436 0.48 12.76 1.364 18.954 c -11.222 -2.024 -22.766 -3.138 -34.57 -3.138 C -489.266 -110.359 -576 -23.5707 -576 83.4853 C -576 190.547 -489.266 277.333 -382.27 277.333 l 656.262 0 l 0 -0.012 C 370.13 277.137 448 199.109 448 102.875 Z'
+            const pathArr =str.split(' ');
+            let opath = []
+            pathArr.forEach(item => {
+              if(/[a-zA-Z]/.test(item)){
+              opath.push([item])
+            }else {
+              opath[opath.length - 1].push(parseFloat(item))
+            }
+            });
+
+          opath.forEach(item => {
+            item.forEach((p,i) => {
+              if (i > 0) {
+                item [i] = item[i] / 3  ;
+              }
+            });
+          });
+          const keyShape = group.addShape("path", {
+            attrs: {
+              ...cfg.style,
+              width: cfg.style.width,
+              height: cfg.style.height,
+              path:  opath,
+            },
+            id: cfg.id,
+            name: "cloud",
+          });
+          group.addShape("text", {
+            attrs: {
+              x: 0,
+              y:  -100,
+              textAlign: "center",
+              text: cfg.label,
+              fill: '#303133',
+            },
+            name: "hubCombo-label",
+          });
+          return keyShape;
+        },
+        
+      },
+      "single-combo"
+    );
+   
+}
+
+ //节点文本溢出省略处理
+ export function fittingString(str, maxWidth, fontSize){
+  const ellipsis = '...';
+  const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
+  let currentWidth = 0;
+  let res = str;
+  const pattern = new RegExp('[\\u4E00-\\u9FA5]+');  
+  str.split('').forEach((letter, i) => {
+    if (currentWidth > maxWidth - ellipsisLength) return;
+    if (pattern.test(letter)) {
+      currentWidth += fontSize;
+    } else {
+      currentWidth += G6.Util.getLetterWidth(letter, fontSize);
+    }
+    if (currentWidth > maxWidth - ellipsisLength) {
+      res = \`\${str.substr(0, i)}\${ellipsis}\`;
+    }
+  });
+  return res;
+}
//registerElements.js
+import G6 from "@antv/g6";
+//共同节点注册
+export  function commonRegister(){
+  // 注册实线动画
+  G6.registerEdge("animate-line",
+    {
+      drawShape(cfg, group) {
+        const self = this;
+        let shapeStyle = self.getShapeStyle(cfg);
+        shapeStyle = Object.assign(shapeStyle, {
+          opacity: 0,
+          strokeOpacity: 0,
+        });
+        const keyShape = group.addShape("path", {
+          attrs: shapeStyle,
+          name: "path-shape",
+        });
+        return keyShape;
+      },
+      afterDraw(cfg, group) {
+        const shape = group.get("children")[0];
+        //线条动画
+        shape.animate(
+          (ratio) => {
+            const opacity = ratio * cfg.style.opacity;
+            const strokeOpacity = ratio * cfg.style.strokeOpacity;
+            return {
+              opacity: ratio || opacity,
+              strokeOpacity: ratio || strokeOpacity,
+            };
+          },
+          {
+            duration: 300,
+          }
+        );
+        //箭头动画
+        const startPoint = shape.getPoint(0);
+        const circle = group.addShape("circle", {
+          attrs: {
+            x: startPoint.x,
+            y: startPoint.y,
+            fill: "#1890ff",
+            r: 2,
+          },
+          name: "circle-shape",
+        });
+        circle.animate(
+          (ratio) => {
+            const tmpPoint = shape.getPoint(ratio);
+            return {
+              x: tmpPoint.x,
+              y: tmpPoint.y,
+            };
+          },
+          {
+            repeat: true,
+            duration: 3000,
+          }
+        );
+      },
+      setState(name, value, item) {
+        const shape = item.get("keyShape");
+        if (name === "disappearing" && value) {
+          shape.animate(
+            (ratio) => {
+              return {
+                opacity: 1 - ratio,
+                strokeOpacity: 1 - ratio,
+              };
+            },
+            {
+              duration: 200,
+            }
+          );
+        } else if (name === "dark") {
+          if (value) shape.attr("opacity", 0.2);
+          else shape.attr("opacity", 1);
+        }
+      },
+    },
+    "line"
+  );
+  //注册iconfont节点
+  G6.registerNode("iconfontHub", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle ,size } = cfg;
+      group.addShape("circle", {
+        attrs: {
+          x: 0,
+          y: size / 2,
+          r: size,
+        },
+        name: "hub-bg-shape",
+      });
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: size  / 2,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          text: cfg.text,
+          fontSize: Math.round(size),
+          ...style,
+        },
+        name: "hub-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: Math.round(size/4),
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "hub-label",
+      });
+      return keyShape;
+    },
+    // afterDraw(cfg, group) {
+    //   const shape = group.get('children')[0];
+    //   shape.animate(
+    //     (ratio) => {
+    //       let fill = '#C396ED'
+    //       if(ratio > 0.6){
+    //         fill = '#FFCF8B'
+    //       }else if(ratio > 0.3){
+    //         fill = '#C396ED'
+    //       }else {
+    //         fill = '#75D882'
+    //       }
+    //       return {
+    //         fill,
+    //       };
+    //     },
+    //     {
+    //       repeat: true,
+    //       duration: 1500,
+    //       // easing: 'easeCubic',
+    //     },
+    //   );
+    // },
+  });
+  //自定义节点和节点动画
+  G6.registerNode( "vpe-rect-animate",
+    {
+    afterDraw(cfg, group) {
+      const { width, height, stroke, radius } = this.getShapeStyle(cfg);
+      const x = -width / 2,
+        y = -height / 2;
+      const back1 = group.addShape("rect", {
+        zIndex: -3,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback1-shape",
+      });
+      const back2 = group.addShape("rect", {
+        zIndex: -2,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback2-shape",
+      });
+      const back3 = group.addShape("circle", {
+        zIndex: -1,
+        attrs: {
+          x: x,
+          y: y,
+          width: width,
+          height: height,
+          fill: stroke,
+          opacity: 0.6,
+          radius,
+        },
+        name: "rback3-shape",
+      });
+      group.sort(); // Sort according to the zIndex
+      back1.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: -300,
+          repeat: true, // repeat
+        }
+      ); // no delay
+      back2.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 1000,
+          repeat: true,  
+        }
+      );  
+      back3.animate(
+        {
+          width: width + 10,
+          height: height + 10,
+          opacity: 0.1,
+          x: x - 5,
+          y: y - 5,
+        },
+        {
+          duration: 3000,
+          easing: "easeCubic",
+          delay: 2000,
+          repeat: true, // repeat
+        }
+      ); // 3s delay
+    },
+  },
+  "rect"
+);
+}
+//弹窗特有节点注册
+export function dialogRegister(){
+   //注册iconfont节点
+   G6.registerNode("iconfontCpe", {
+    draw(cfg, group) {
+      const { style, labelCfg: labelStyle } = cfg;
+      //添加图标
+      const keyShape = group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 0,
+          fontFamily: "iconfont",
+          textAlign: "center",
+          textBaseline: "middle",
+          text: cfg.text,
+          fontSize: cfg.size,
+          ...style,
+        },
+        name: "cpe-shape",
+      });
+      //添加label
+      group.addShape("text", {
+        attrs: {
+          x: 0,
+          y: 10,
+          textAlign: "center",
+          text: cfg.label,
+          ...labelStyle.style,
+        },
+        name: "cpe-label",
+      });
+  
+      return keyShape;
+    },
+    afterDraw(cfg, group) {
+      const shape = group.get('children')[0];
+      shape.animate(
+        (ratio) => {
+          let text = '\\ue604'
+          if(ratio > 0.6){
+            text = '\\ue604'
+          }else if(ratio > 0.3){
+            text = '\\ue606'
+          }else {
+            text = '\\ue605'
+          }
+          return {
+            text,
+          };
+        },
+        {
+          repeat: true,
+          duration: 1500,
+          delay: 3000,
+          // easing: 'easeCubic',
+        },
+      );
+    },
+  });
+  //注册虚线动画
+  // G6.registerEdge("vpn-line-dash",
+  //   {
+  //     afterDraw(cfg, group) {
+  //       const shape = group.get("children")[0];
+  //       let index = 0;
+  //       shape.animate(
+  //         () => {
+  //           index = index+0.2;
+  //           if (index > 9) {
+  //             index = 0;
+  //           }
+  //           const res = {
+  //             lineDash: [4, 4],
+  //             lineDashOffset: -index,
+  //           };
+  //           return res;
+  //         },
+  //         {
+  //           repeat: true,
+  //           duration:10000,
+  //         }
+  //       );
+  //     },
+  //   },
+  //   "line"
+  // );
+}
+
+//网络拓扑总览特有节点注册
+export function viewRegister(){
+  //注册iconfont combos
+  // G6.registerCombo("cloudCombo",
+  //   {
+  //     drawShape: function drawShape(cfg, group) {
+  //       // const {  labelCfg: labelStyle   } = cfg;
+  //       const keyShape = group.addShape("text", { 
+  //         attrs: {
+  //           y: 0,
+  //           x: 0,
+  //           fill: cfg.style.fill,
+  //           stroke: cfg.style.fill,
+  //           fontFamily: "iconfont",
+  //           textAlign: "center",
+  //           textBaseline: "middle",
+  //           text: "\\ue603",
+  //           fontSize: 320,
+  //           zIndex: 8,
+  //         },
+  //         name: "cloud",
+  //       });
+  //           //添加label
+  //     // group.addShape("text", {
+  //     //   attrs: {
+  //     //     x: 0,
+  //     //     y: -80,
+  //     //     textAlign: "center",
+  //     //     textBaseline: "middle",
+  //     //     text: cfg.label,
+  //     //     ...labelStyle.style,
+  //     //   },
+  //     //   name: "hubCombo-label",
+  //     // });
+  //       return keyShape;
+  //     },
+  //   },
+  //   "cicle"
+  // );
+    //注册SVG combo
+  G6.registerCombo(
+      "cloudCombo",
+      {
+        drawShape: function drawShape(cfg, group) {
+          const { labelCfg  } = cfg;
+          let str = 'M 448 102.875 c 0 -82.09 -56.678 -150.9 -132.996 -169.48 C 311.762 -195.305 206.546 -298.667 77.142 -298.667 c -75.792 0 -143.266 35.494 -186.854 90.732 c -24.442 -31.598 -62.69 -51.96 -105.708 -51.96 c -73.81 0 -133.642 59.874 -133.642 133.722 c 0 6.436 0.48 12.76 1.364 18.954 c -11.222 -2.024 -22.766 -3.138 -34.57 -3.138 C -489.266 -110.359 -576 -23.5707 -576 83.4853 C -576 190.547 -489.266 277.333 -382.27 277.333 l 656.262 0 l 0 -0.012 C 370.13 277.137 448 199.109 448 102.875 Z'
+            const pathArr =str.split(' ');
+            let opath = []
+            pathArr.forEach(item => {
+              if(/[a-zA-Z]/.test(item)){
+              opath.push([item])
+            }else {
+              opath[opath.length - 1].push(parseFloat(item))
+            }
+            });
+
+          opath.forEach(item => {
+            item.forEach((p,i) => {
+              if (i > 0) {
+                item [i] = item[i] / 3  ;
+              }
+            });
+          });
+          const keyShape = group.addShape("path", {
+            attrs: {
+              ...cfg.style,
+              width: cfg.style.width,
+              height: cfg.style.height,
+              path:  opath,
+            },
+            id: cfg.id,
+            name: "cloud",
+          });
+          group.addShape("text", {
+            attrs: {
+              x: 0,
+              y:  -100,
+              textAlign: "center",
+              text: cfg.label,
+              fill: '#303133',
+            },
+            name: "hubCombo-label",
+          });
+          return keyShape;
+        },
+        
+      },
+      "single-combo"
+    );
+   
+}
+
+ //节点文本溢出省略处理
+ export function fittingString(str, maxWidth, fontSize){
+  const ellipsis = '...';
+  const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
+  let currentWidth = 0;
+  let res = str;
+  const pattern = new RegExp('[\\u4E00-\\u9FA5]+');  
+  str.split('').forEach((letter, i) => {
+    if (currentWidth > maxWidth - ellipsisLength) return;
+    if (pattern.test(letter)) {
+      currentWidth += fontSize;
+    } else {
+      currentWidth += G6.Util.getLetterWidth(letter, fontSize);
+    }
+    if (currentWidth > maxWidth - ellipsisLength) {
+      res = \`\${str.substr(0, i)}\${ellipsis}\`;
+    }
+  });
+  return res;
+}
`,6),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.lean.js" "b/assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.lean.js" new file mode 100644 index 00000000..68245bd4 --- /dev/null +++ "b/assets/Problem_Graphical_Antv\344\273\243\347\240\201\347\211\207\346\256\265\351\233\206\351\224\246.md.3d28f150.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"网络拓扑图代码","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Graphical/Antv代码片段集锦.md","filePath":"Problem/Graphical/Antv代码片段集锦.md"}'),p={name:"Problem/Graphical/Antv代码片段集锦.md"},o=l("",6),e=[o];function t(c,r,y,A,D,B){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.js" "b/assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.js" new file mode 100644 index 00000000..b29af436 --- /dev/null +++ "b/assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.js" @@ -0,0 +1,25 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const d=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Graphical/Antv使用总结.md","filePath":"Problem/Graphical/Antv使用总结.md"}'),p={name:"Problem/Graphical/Antv使用总结.md"},o=l(`

一、默认收缩二级节点

js
//树形图哪个需要收缩则把属性collapsed设置为true
+data.children.forEach(item => item.collapsed = true)
//树形图哪个需要收缩则把属性collapsed设置为true
+data.children.forEach(item => item.collapsed = true)

二、改用iconfont文字不居中问题

js
//注册节点添加label图形时动态计算label位置
+ group.addShape("text", {
+   attrs: {
+     x: 0,
+     y: -80,
+   textAlign: "center",
+   textBaseline: "middle",
+    text: cfg.label,
+   ...labelStyle.style,//这里需要重新处理x,y
+ },
+  name: "hubCombo-label",
+});
//注册节点添加label图形时动态计算label位置
+ group.addShape("text", {
+   attrs: {
+     x: 0,
+     y: -80,
+   textAlign: "center",
+   textBaseline: "middle",
+    text: cfg.label,
+   ...labelStyle.style,//这里需要重新处理x,y
+ },
+  name: "hubCombo-label",
+});

三、初始化画图完成后出现这个锯齿

`,5),e=[o];function t(c,r,y,A,i,D){return a(),n("div",null,e)}const E=s(p,[["render",t]]);export{d as __pageData,E as default}; diff --git "a/assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.lean.js" "b/assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.lean.js" new file mode 100644 index 00000000..e612a877 --- /dev/null +++ "b/assets/Problem_Graphical_Antv\344\275\277\347\224\250\346\200\273\347\273\223.md.10b596c9.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const d=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Graphical/Antv使用总结.md","filePath":"Problem/Graphical/Antv使用总结.md"}'),p={name:"Problem/Graphical/Antv使用总结.md"},o=l("",5),e=[o];function t(c,r,y,A,i,D){return a(),n("div",null,e)}const E=s(p,[["render",t]]);export{d as __pageData,E as default}; diff --git "a/assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.js" "b/assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.js" new file mode 100644 index 00000000..1b33faf3 --- /dev/null +++ "b/assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.js" @@ -0,0 +1,219 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"Echarts问题总结","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Graphical/Echarts问题总结.md","filePath":"Problem/Graphical/Echarts问题总结.md"}'),p={name:"Problem/Graphical/Echarts问题总结.md"},o=l(`

Echarts问题总结

屏幕适配问题

方案一: 使用scss函数计算比例

scss
//默认设计稿的宽度
+$designWidth:1920;
+//默认设计稿的高度
+$designHeight:1080;
+
+//px转为vw的函数
+@function vw($px) {
+  @return math.div($px , $designWidth) * 100vw;
+}
+
+//px转为vh的函数
+@function vh($px) {
+  @return math.div($px , $designHeight) * 100vh;
+}
//默认设计稿的宽度
+$designWidth:1920;
+//默认设计稿的高度
+$designHeight:1080;
+
+//px转为vw的函数
+@function vw($px) {
+  @return math.div($px , $designWidth) * 100vw;
+}
+
+//px转为vh的函数
+@function vh($px) {
+  @return math.div($px , $designHeight) * 100vh;
+}

左侧菜单折叠响应式

js
 mounted() {
+// 监听窗口大小,所有echart实例尺寸尺寸改变
+    window.addEventListener("resize", () => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    });
+  //监听div容器的无效
+   /*this.$refs.onlineIspRef.addEventListener("resize",() => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    })*/
+}
 mounted() {
+// 监听窗口大小,所有echart实例尺寸尺寸改变
+    window.addEventListener("resize", () => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    });
+  //监听div容器的无效
+   /*this.$refs.onlineIspRef.addEventListener("resize",() => {
+      this.chartsInstance.forEach(chart => {
+        chart.resize()
+      });
+    })*/
+}

方案: 侧边栏按钮点击展开/折叠时, 手动触发window.resize

js
 toggleLeftMenu() {
+      Cookies.set('sidebar', this.leftMenuOpen ? 'close' : 'open', {path: '/'});
+      this.$store.commit('toggleLeftMenu', !this.leftMenuOpen);
+      this.doResize()
+  },
+doResize(){ 
+    setTimeout(function(){
+          var ev = new Event("resize", {"bubbles":true, "cancelable":false});
+          window.dispatchEvent(ev);
+      },120);//不使用定时器没反应
+    
+    //有效, 而且提示event.initEvent方法已经过时(deprecated)
+    //但是折线图左侧收缩/延伸会有抖动问题,需要调节定时器时间使比较不突兀
+  /*setTimeout(function(){
+      if(document.createEvent) {
+          var event = document.createEvent("HTMLEvents");
+          event.initEvent("resize", true, true);
+          window.dispatchEvent(event);
+      } else if(document.createEventObject) {
+          window.fireEvent("onresize");
+      }
+  },120);*/
+    
+},
 toggleLeftMenu() {
+      Cookies.set('sidebar', this.leftMenuOpen ? 'close' : 'open', {path: '/'});
+      this.$store.commit('toggleLeftMenu', !this.leftMenuOpen);
+      this.doResize()
+  },
+doResize(){ 
+    setTimeout(function(){
+          var ev = new Event("resize", {"bubbles":true, "cancelable":false});
+          window.dispatchEvent(ev);
+      },120);//不使用定时器没反应
+    
+    //有效, 而且提示event.initEvent方法已经过时(deprecated)
+    //但是折线图左侧收缩/延伸会有抖动问题,需要调节定时器时间使比较不突兀
+  /*setTimeout(function(){
+      if(document.createEvent) {
+          var event = document.createEvent("HTMLEvents");
+          event.initEvent("resize", true, true);
+          window.dispatchEvent(event);
+      } else if(document.createEventObject) {
+          window.fireEvent("onresize");
+      }
+  },120);*/
+    
+},

地图缩放重叠问题

Echart文档参考

js
export default {
+	geo: {
+		roam: true,
+		map: "china",
+		aspectScale: 0.75,  
+		zoom: 1.1,
+		itemStyle: {
+			normal: {
+				shadowColor: "#ddd",
+				shadowOffsetX: 5,
+				shadowOffsetY: 5,
+			},
+		},
+		regions: [
+			{
+				name: "南海诸岛",
+				itemStyle: {
+					areaColor: "rgba(0, 10, 52, 1)",
+					borderColor: "rgba(0, 10, 52, 1)",
+					normal: {
+						opacity: 0,
+						label: {
+							show: false,
+							color: "#009cc9",
+						},
+					},
+				},
+			},
+		],
+	},
+	series: [
+		{
+			type: "map",
+			geoIndex: 0, //方案一:设置这个属性
+			label: {
+				normal: {
+					show: true,
+					textStyle: {
+						color: "#666",
+					},
+				},
+				emphasis: {
+					textStyle: {
+						color: "#fff",  
+					},
+				},
+			},
+			itemStyle: {
+				normal: {
+					borderType: "dashed",
+				},
+				emphasis: {
+					areaColor: "#3777DD",
+					borderWidth: 0.1,
+				},
+			},
+			zoom: 1.1,
+			map: "china", // //方案二:删除这个属性
+		},
+	],
+}
export default {
+	geo: {
+		roam: true,
+		map: "china",
+		aspectScale: 0.75,  
+		zoom: 1.1,
+		itemStyle: {
+			normal: {
+				shadowColor: "#ddd",
+				shadowOffsetX: 5,
+				shadowOffsetY: 5,
+			},
+		},
+		regions: [
+			{
+				name: "南海诸岛",
+				itemStyle: {
+					areaColor: "rgba(0, 10, 52, 1)",
+					borderColor: "rgba(0, 10, 52, 1)",
+					normal: {
+						opacity: 0,
+						label: {
+							show: false,
+							color: "#009cc9",
+						},
+					},
+				},
+			},
+		],
+	},
+	series: [
+		{
+			type: "map",
+			geoIndex: 0, //方案一:设置这个属性
+			label: {
+				normal: {
+					show: true,
+					textStyle: {
+						color: "#666",
+					},
+				},
+				emphasis: {
+					textStyle: {
+						color: "#fff",  
+					},
+				},
+			},
+			itemStyle: {
+				normal: {
+					borderType: "dashed",
+				},
+				emphasis: {
+					areaColor: "#3777DD",
+					borderWidth: 0.1,
+				},
+			},
+			zoom: 1.1,
+			map: "china", // //方案二:删除这个属性
+		},
+	],
+}
`,12),t=[o];function e(c,r,y,A,D,i){return n(),a("div",null,t)}const C=s(p,[["render",e]]);export{B as __pageData,C as default}; diff --git "a/assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.lean.js" "b/assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.lean.js" new file mode 100644 index 00000000..d4a18f6f --- /dev/null +++ "b/assets/Problem_Graphical_Echarts\351\227\256\351\242\230\346\200\273\347\273\223.md.fe67d408.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const B=JSON.parse('{"title":"Echarts问题总结","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Graphical/Echarts问题总结.md","filePath":"Problem/Graphical/Echarts问题总结.md"}'),p={name:"Problem/Graphical/Echarts问题总结.md"},o=l("",12),t=[o];function e(c,r,y,A,D,i){return n(),a("div",null,t)}const C=s(p,[["render",e]]);export{B as __pageData,C as default}; diff --git "a/assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.js" "b/assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.js" new file mode 100644 index 00000000..4965b980 --- /dev/null +++ "b/assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.js" @@ -0,0 +1,73 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Nuxt3/Nuxt3项目踩坑.md","filePath":"Problem/Nuxt3/Nuxt3项目踩坑.md"}'),p={name:"Problem/Nuxt3/Nuxt3项目踩坑.md"},o=l(`

Uncaught TypeError: Cannot read properties of undefined (reading 'prototype')

2023-05-19-14-49-43

js
//uno.config.ts
+shortcuts: [["f-s-c", "flex justify-start items-center"]];
//uno.config.ts
+shortcuts: [["f-s-c", "flex justify-start items-center"]];
  1. 写在类名上不生效
html
<!--f-s-c 直接写在类名上不生效-->
+<div class="hidden lg:f-c-c">Test</div>
<!--f-s-c 直接写在类名上不生效-->
+<div class="hidden lg:f-c-c">Test</div>
  1. 写在 CSS 上报错
html
<div class="nav">Test</div>
<div class="nav">Test</div>
css
// f-s-c 报错;The \`xl:f-c-c\` class does not exist. If \`xl:f-c-c\` is a custom class, make sure it is defined within a \`@layer\` directive.
+
+.nav {
+  @apply hidden lg:f-c-c;
+}
// f-s-c 报错;The \`xl:f-c-c\` class does not exist. If \`xl:f-c-c\` is a custom class, make sure it is defined within a \`@layer\` directive.
+
+.nav {
+  @apply hidden lg:f-c-c;
+}

解决方法:断点后不写自定义的

html
<div class="hidden lg:flex justify-center items-center">Test</div>
<div class="hidden lg:flex justify-center items-center">Test</div>

总结:自定义的类名快捷键不能写在变体后面

hidden 与自定义变体不能一起用

ts
//uno.config.ts
+shortcuts: [
+  ["f-s-c", "flex justify-start items-center"],
+  ["f-c-c", "flex justify-center items-center"],
+];
//uno.config.ts
+shortcuts: [
+  ["f-s-c", "flex justify-start items-center"],
+  ["f-c-c", "flex justify-center items-center"],
+];
html
<div class="hidden xl:f-c-c">TEST</div>
<div class="hidden xl:f-c-c">TEST</div>

可以这样用

html
<div class="f-s-c xl:f-c-c">TEST</div>
<div class="f-s-c xl:f-c-c">TEST</div>

项目一直报 Element 相关错误

element-ui.js:1 Uncaught TypeError: Cannot read properties of undefined (reading 'prototype')2023-05-21-20-26-38 换浏览器后没报错,定位到可能是浏览器插件的原因,果然排除法找到是:YouTube 视频摘要 ChatGPT 生成-快速笔记 (中文版) 的问题!

跨域问题

js
export default defineNuxtConfig({
+  /* ... */
+  nitro: {
+    devProxy: {
+      '/account/api': {
+        target: 'http://192.168.211.63/account/api',
+       // target: 'http://192.168.211.63', 【不生效】 不同于 vite,这样配置到达 nginx 是 '/'
+        ws: false,
+        changeOrigin: true,
+      },
+    },
+  }
+})
export default defineNuxtConfig({
+  /* ... */
+  nitro: {
+    devProxy: {
+      '/account/api': {
+        target: 'http://192.168.211.63/account/api',
+       // target: 'http://192.168.211.63', 【不生效】 不同于 vite,这样配置到达 nginx 是 '/'
+        ws: false,
+        changeOrigin: true,
+      },
+    },
+  }
+})
js
//业务请求
+async function getImgCode() {
+  const data = await useFetch('/account/api/getImageCode', {
+    method: 'POST',
+    body:{},
+  })
+  return data.data.value
+}
//业务请求
+async function getImgCode() {
+  const data = await useFetch('/account/api/getImageCode', {
+    method: 'POST',
+    body:{},
+  })
+  return data.data.value
+}

nuxt-simple-sitemap插件使用问题

打包时报错:解析到错误 URL

js
nitro: {
+    prerender: {
+      crawlLinks: true,
+      routes: ['/'], //去掉: ,'sitemap.xml'
+    },
+}
nitro: {
+    prerender: {
+      crawlLinks: true,
+      routes: ['/'], //去掉: ,'sitemap.xml'
+    },
+}

测试环境能访问sitemap.xml 页面 但是线上环境访问不到,报相关错误:/__sitemap__/routes.json ,需要在 nginx 配置 IP 和主机名的传送。

zsh
  # nginx.conf
+   proxy_set_header X-Real-IP $remote_addr;
+   proxy_set_header Host $host;
  # nginx.conf
+   proxy_set_header X-Real-IP $remote_addr;
+   proxy_set_header Host $host;
`,26),e=[o];function t(c,r,y,i,d,A){return a(),n("div",null,e)}const u=s(p,[["render",t]]);export{E as __pageData,u as default}; diff --git "a/assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.lean.js" "b/assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.lean.js" new file mode 100644 index 00000000..0f181a96 --- /dev/null +++ "b/assets/Problem_Nuxt3_Nuxt3\351\241\271\347\233\256\350\270\251\345\235\221.md.e3bdda07.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/Nuxt3/Nuxt3项目踩坑.md","filePath":"Problem/Nuxt3/Nuxt3项目踩坑.md"}'),p={name:"Problem/Nuxt3/Nuxt3项目踩坑.md"},o=l("",26),e=[o];function t(c,r,y,i,d,A){return a(),n("div",null,e)}const u=s(p,[["render",t]]);export{E as __pageData,u as default}; diff --git "a/assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.js" "b/assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.js" new file mode 100644 index 00000000..34af7d88 --- /dev/null +++ "b/assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.js" @@ -0,0 +1,307 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"VitePress踩坑记录","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/VitePress/VitePress踩坑记录.md","filePath":"Problem/VitePress/VitePress踩坑记录.md"}'),p={name:"Problem/VitePress/VitePress踩坑记录.md"},o=l(`

VitePress踩坑记录

ERR_INVALID_FILE_URL_HOST

DANGER

执行打包命令时,出现此错误 TypeError [ERR_INVALID_FILE_URL_HOST]: File URL host must be "localhost" or empty on darwin

形成原因:全局替换时粗心大意造成img src属性多了个'/'

解决

TIP

刚开始我只能猜到某个文件路径有问题 ,又不知道那个文件有问题,最后用上了 排除法 逐个移除文章文件夹最终才定位到出问题的文档。 虽然问题解决的的过程有点费劲,不得不说当问题搞得人想撞墙的时候,无疑也是一个不错的思路和方法!!!

删除多余的'/'就好了,自己解决自己的 issues !!!

实现自动生成文章左侧侧边栏

痛点及需求

WARNING

​ 每次添加文章过程:对应的目录下添加.md文, 修改themeConfig的sidebar属性,给对象加上新增的文章映射

​ 添加的文章少还好,多了的话就显得很麻烦不够优雅,所有想写个脚本按照目录结构自动生产对应的映射关系。

想法及实现

在package.json添加脚本执行命令

image-20230205230548188

在博客根目录新建scripts目录并创建文件getSidebar.ts,添加如下代码

js
/********   读取 zerdocs/docs/ 下的所有文件夹,自动生成侧边栏sidebar.ts文件   ***********/
+
+
+const fs = require('fs')
+const path = require('path')
+
+let sidebarObj = {}
+
+//生成一级分组 
+let topDirArr = fs.readdirSync(path.resolve(__dirname, '../docs')).filter((item) => isArticleDir(item))
+topDirArr.forEach((item) => {
+  if (!sidebarObj[\`/\${item}/\`]) {
+    sidebarObj[\`/\${item}/\`] = []
+  }
+})
+
+const sidebars = deepGetFile(path.resolve(__dirname, '../docs')) // 读取 docs 目录下的所有文件夹
+const sidebarlist = deepGenerateSidebar(sidebars)
+
+//写入到docs/.vitepress/sidebar/index.ts
+
+//把数组里面的每个对象合并到一个对象里面
+let sidebar = sidebarlist.reduce((pre, cur) => Object.assign(pre, cur), {})
+Object.entries(sidebar).forEach(([key, items]) => {
+  let keyArr = splitPath(key)
+  let text = keyArr[keyArr.length - 1]
+  if(sidebarObj[\`/\${keyArr[0]}/\`]){
+    sidebarObj[\`/\${keyArr[0]}/\`].push({
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    })
+  }else{
+    sidebarObj[\`/\${keyArr[0]}/\`] = [{
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    }]
+  }
+})
+
+const sidebarStr = JSON.stringify(sidebarObj, null, 2)
+//把sidebarStr写入到docs/.vitepress/sidebar/index.ts
+const sidebarPath = path.resolve(__dirname, '../docs/.vitepress/sidebar/index.ts')
+
+//没有则创建
+if (!fs.existsSync(sidebarPath)) {
+  fs.mkdirSync(path.resolve(__dirname, '../docs/.vitepress/sidebar'))
+}
+
+fs.writeFileSync(sidebarPath, \`export default \${sidebarStr}\`)
+
+//判断是否是文件夹
+function isArticleDir(dir) {
+  let exclude = ['public', 'index.md','vite.config.ts']  //排除的文件夹
+  return !exclude.includes(dir) && !dir.startsWith('.')
+}
+
+function splitPath(path) {
+  return path.split('/').filter((item) => item !== '')
+}
+function deepGetFile(dir) {
+  let backList = []
+  let list = fs.readdirSync(dir).filter((item) => isArticleDir(item))
+
+  for (let index in list) {
+    let item = path.resolve(dir, list[index])
+    if (fs.statSync(item).isDirectory()) {
+      backList = backList.concat(deepGetFile(item))
+    } else {
+      //输出相对路径
+      item = item.replace(path.resolve(__dirname, '../docs'), '').replace(/\\\\/g, '/')
+      backList.push(item)
+    }
+  }
+  return backList
+}
+
+// 生成侧边栏
+function deepGenerateSidebar(arr) {
+  //递归按照最后一级目录生成侧边栏
+  const sidebar = {}
+  sidebars.forEach((item) => {
+    const [dir, ...rest] = splitPath(item)
+    if (!sidebar[dir]) {
+      sidebar[dir] = []
+    }
+    sidebar[dir].push(item)
+  })
+  let sidebarList = []
+  //按最后一级目录分组
+  for (let key in sidebar) {
+    let pathPice = sidebar[key].map((item) => splitPath(item))
+    //如果pathPice[pathPice.length-1]相同,则合并
+    pathPice = pathPice.reduce((pre, cur) => {
+      let dirStr = cur.slice(0, -1).join('/') // /problem/vueproject/
+      let text = cur[cur.length - 1].replace(/\\.md$/, '')
+      let link = '/' + cur.join('/').replace(/\\.md$/, '')
+      pre[dirStr] = pre[dirStr] ? [...pre[dirStr], { text, link }] : [{ text, link }]
+      return pre
+    }, {})
+    sidebarList.push(pathPice)
+  }
+  return sidebarList
+}
/********   读取 zerdocs/docs/ 下的所有文件夹,自动生成侧边栏sidebar.ts文件   ***********/
+
+
+const fs = require('fs')
+const path = require('path')
+
+let sidebarObj = {}
+
+//生成一级分组 
+let topDirArr = fs.readdirSync(path.resolve(__dirname, '../docs')).filter((item) => isArticleDir(item))
+topDirArr.forEach((item) => {
+  if (!sidebarObj[\`/\${item}/\`]) {
+    sidebarObj[\`/\${item}/\`] = []
+  }
+})
+
+const sidebars = deepGetFile(path.resolve(__dirname, '../docs')) // 读取 docs 目录下的所有文件夹
+const sidebarlist = deepGenerateSidebar(sidebars)
+
+//写入到docs/.vitepress/sidebar/index.ts
+
+//把数组里面的每个对象合并到一个对象里面
+let sidebar = sidebarlist.reduce((pre, cur) => Object.assign(pre, cur), {})
+Object.entries(sidebar).forEach(([key, items]) => {
+  let keyArr = splitPath(key)
+  let text = keyArr[keyArr.length - 1]
+  if(sidebarObj[\`/\${keyArr[0]}/\`]){
+    sidebarObj[\`/\${keyArr[0]}/\`].push({
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    })
+  }else{
+    sidebarObj[\`/\${keyArr[0]}/\`] = [{
+      text,
+      collapsible: true,
+      collapsed: false,
+      items,
+    }]
+  }
+})
+
+const sidebarStr = JSON.stringify(sidebarObj, null, 2)
+//把sidebarStr写入到docs/.vitepress/sidebar/index.ts
+const sidebarPath = path.resolve(__dirname, '../docs/.vitepress/sidebar/index.ts')
+
+//没有则创建
+if (!fs.existsSync(sidebarPath)) {
+  fs.mkdirSync(path.resolve(__dirname, '../docs/.vitepress/sidebar'))
+}
+
+fs.writeFileSync(sidebarPath, \`export default \${sidebarStr}\`)
+
+//判断是否是文件夹
+function isArticleDir(dir) {
+  let exclude = ['public', 'index.md','vite.config.ts']  //排除的文件夹
+  return !exclude.includes(dir) && !dir.startsWith('.')
+}
+
+function splitPath(path) {
+  return path.split('/').filter((item) => item !== '')
+}
+function deepGetFile(dir) {
+  let backList = []
+  let list = fs.readdirSync(dir).filter((item) => isArticleDir(item))
+
+  for (let index in list) {
+    let item = path.resolve(dir, list[index])
+    if (fs.statSync(item).isDirectory()) {
+      backList = backList.concat(deepGetFile(item))
+    } else {
+      //输出相对路径
+      item = item.replace(path.resolve(__dirname, '../docs'), '').replace(/\\\\/g, '/')
+      backList.push(item)
+    }
+  }
+  return backList
+}
+
+// 生成侧边栏
+function deepGenerateSidebar(arr) {
+  //递归按照最后一级目录生成侧边栏
+  const sidebar = {}
+  sidebars.forEach((item) => {
+    const [dir, ...rest] = splitPath(item)
+    if (!sidebar[dir]) {
+      sidebar[dir] = []
+    }
+    sidebar[dir].push(item)
+  })
+  let sidebarList = []
+  //按最后一级目录分组
+  for (let key in sidebar) {
+    let pathPice = sidebar[key].map((item) => splitPath(item))
+    //如果pathPice[pathPice.length-1]相同,则合并
+    pathPice = pathPice.reduce((pre, cur) => {
+      let dirStr = cur.slice(0, -1).join('/') // /problem/vueproject/
+      let text = cur[cur.length - 1].replace(/\\.md$/, '')
+      let link = '/' + cur.join('/').replace(/\\.md$/, '')
+      pre[dirStr] = pre[dirStr] ? [...pre[dirStr], { text, link }] : [{ text, link }]
+      return pre
+    }, {})
+    sidebarList.push(pathPice)
+  }
+  return sidebarList
+}

VitePress添加本地搜索功能

WARNING

折腾了三遍Algolia都没能添加上搜索功能,最后在找到了这个issus里大佬提供的解决方案,成功添加上了本地搜索功能。

安装插件

bash
npm i vitepress-plugin-search markdown-it flexsearch -D
npm i vitepress-plugin-search markdown-it flexsearch -D

添加和配置插件

坑点

1.README 没写在哪个目录下存放vite.config.ts,依据经验放在根目录下不管用,放在.vitepress也不生效,最后挨个试才发现需要放在docs

2.示例没有引入flexSearchIndexOptions,需要手动从flexsearch中引入

3.引入后发现之前搜索框样式没了,需要在.vitepress/theme/styles/index.css下重新覆盖样式

image-20230205233032922

typescript

+//vite.config.ts
+import { SearchPlugin } from "vitepress-plugin-search";
+import { defineConfig } from "vite";
+import flexSearchIndexOptions   from "flexsearch";
+//default options
+var options = {
+  ...flexSearchIndexOptions,
+  previewLength: 100,//搜索结果预览长度
+  buttonLabel: "搜索",
+  placeholder: "情输入关键词",
+};
+
+export default defineConfig({
+  plugins: [SearchPlugin(options)],
+});

+//vite.config.ts
+import { SearchPlugin } from "vitepress-plugin-search";
+import { defineConfig } from "vite";
+import flexSearchIndexOptions   from "flexsearch";
+//default options
+var options = {
+  ...flexSearchIndexOptions,
+  previewLength: 100,//搜索结果预览长度
+  buttonLabel: "搜索",
+  placeholder: "情输入关键词",
+};
+
+export default defineConfig({
+  plugins: [SearchPlugin(options)],
+});

样式覆盖

css
.DocSearch-Button {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin: 0;
+  padding: 0;
+  width: 32px;
+  height: 32px;
+  border-radius: 4px;
+  background: transparent;
+  transition: border-color 0.25s;
+}
+@media (min-width: 768px) {
+  .DocSearch-Button {
+    justify-content: flex-start;
+    border: 1px solid transparent;
+    border-radius: 8px;
+    padding: 0 10px 0 12px;
+    width: 100%;
+    height: 40px;
+    background-color: var(--vp-c-bg-alt);
+  }
+}
+@media (max-width: 768px) {
+  .DocSearch-Button-Keys {
+    display: none;
+  }
+  .VPNavBarHamburger{
+    height: 32px !important;
+    width: 32px !important;
+    border-radius: 4px;
+  }
+}
.DocSearch-Button {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin: 0;
+  padding: 0;
+  width: 32px;
+  height: 32px;
+  border-radius: 4px;
+  background: transparent;
+  transition: border-color 0.25s;
+}
+@media (min-width: 768px) {
+  .DocSearch-Button {
+    justify-content: flex-start;
+    border: 1px solid transparent;
+    border-radius: 8px;
+    padding: 0 10px 0 12px;
+    width: 100%;
+    height: 40px;
+    background-color: var(--vp-c-bg-alt);
+  }
+}
+@media (max-width: 768px) {
+  .DocSearch-Button-Keys {
+    display: none;
+  }
+  .VPNavBarHamburger{
+    height: 32px !important;
+    width: 32px !important;
+    border-radius: 4px;
+  }
+}
`,26),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.lean.js" "b/assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.lean.js" new file mode 100644 index 00000000..5012dc3f --- /dev/null +++ "b/assets/Problem_VitePress_VitePress\350\270\251\345\235\221\350\256\260\345\275\225.md.007e02bc.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"VitePress踩坑记录","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/VitePress/VitePress踩坑记录.md","filePath":"Problem/VitePress/VitePress踩坑记录.md"}'),p={name:"Problem/VitePress/VitePress踩坑记录.md"},o=l("",26),e=[o];function t(c,r,y,A,D,i){return n(),a("div",null,e)}const C=s(p,[["render",t]]);export{E as __pageData,C as default}; diff --git "a/assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.js" "b/assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.js" new file mode 100644 index 00000000..9911c64a --- /dev/null +++ "b/assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.js" @@ -0,0 +1,5 @@ +import{_ as s,o as e,c as a,Q as o}from"./chunks/framework.c53372a0.js";const _=JSON.parse('{"title":"VuePress踩坑记录","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/VitePress/VuePress踩坑记录.md","filePath":"Problem/VitePress/VuePress踩坑记录.md"}'),t={name:"Problem/VitePress/VuePress踩坑记录.md"},n=o(`

VuePress踩坑记录

坑点一、自定义目录不能根据视口固定

巨坑

找了好多博客参考,没发现有相关的问题,挠破头皮都没想明白啥原因,还好碰到一篇博客解决了疑惑

WARNING

产生原因:当一个元素position特性值设置为fixed时,如果该元素的先祖容器中存在transform特性值为非none的元素,则

position: fixed; 将相对于该先祖容器定位!!! 最后发现祖先元素有transform: translateY(0px);这行代码在作怪!!

解决方法:自定义样式覆盖就好啦

css
.page>section {
+    transform: none!important;
+}
.page>section {
+    transform: none!important;
+}

坑点二、引用的Gitee图床图片没显示

有人说是图床的问题、防盗链的问题,最后才发现自己把图床项目设为私有的项目了,重新设为开源成功解决

坑点三、Hexo博客源码没有备份,误点VsCode放弃所有更改并且回退版本

天坑

因学习配置博客用git action来自动化部署,配置完后发现打包报错,搞了好久没办法解决。 本来想执行git checkout .,看到VsCode有个快捷按钮,由于之前没有备份博客源码,点了一下直接回到解放前!

领悟

来到了新的阵地VuePress折腾,学到了码农必备技能------备份

`,12),l=[n];function p(c,r,i,d,m,u){return e(),a("div",null,l)}const y=s(t,[["render",p]]);export{_ as __pageData,y as default}; diff --git "a/assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.lean.js" "b/assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.lean.js" new file mode 100644 index 00000000..fc9525b3 --- /dev/null +++ "b/assets/Problem_VitePress_VuePress\350\270\251\345\235\221\350\256\260\345\275\225.md.d7553dcf.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as e,c as a,Q as o}from"./chunks/framework.c53372a0.js";const _=JSON.parse('{"title":"VuePress踩坑记录","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/VitePress/VuePress踩坑记录.md","filePath":"Problem/VitePress/VuePress踩坑记录.md"}'),t={name:"Problem/VitePress/VuePress踩坑记录.md"},n=o("",12),l=[n];function p(c,r,i,d,m,u){return e(),a("div",null,l)}const y=s(t,[["render",p]]);export{_ as __pageData,y as default}; diff --git "a/assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.js" "b/assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.js" new file mode 100644 index 00000000..aac13ec7 --- /dev/null +++ "b/assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.js" @@ -0,0 +1,405 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"Vue项目踩坑一","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/VueProject/Vue项目踩坑一.md","filePath":"Problem/VueProject/Vue项目踩坑一.md"}'),p={name:"Problem/VueProject/Vue项目踩坑一.md"},o=l(`

Vue项目踩坑一

webpack-bundle-analyzer插件

安装后使用完把--report参数去掉,还是会给你生成打包文件,并会提示8888端口被占用,

需要在vue.config.js注释插件的使用,才能不被影响

点击弹窗父子传值成功,但是数据没有展示

恰巧性能优化,后端改动了大量的关联关系,刚开始以为后端改动数据层级嵌套太深vue丢失了响应式的原因,

最后才发现是前端element-ui全局引入改为按需引入, DescriptionsItem 组件漏写了(没有警告、报错提示,巨坑)

html
  <el-dialog
+  :title="title"
+  :visible="visible"
+   :before-close="close"  :close-on-click-modal="false">    
+   <el-descriptions   border>
+        <!--在main.js漏了导入并使用DescriptionsItem-->
+        <el-descriptions-item label="ID"> {{accountInfo.id}} </el-descriptions-item>
+        <el-descriptions-item label="name"> {{accountInfo.name}} </el-descriptions-item>
+    </el-descriptions>
+</el-dialog>
  <el-dialog
+  :title="title"
+  :visible="visible"
+   :before-close="close"  :close-on-click-modal="false">    
+   <el-descriptions   border>
+        <!--在main.js漏了导入并使用DescriptionsItem-->
+        <el-descriptions-item label="ID"> {{accountInfo.id}} </el-descriptions-item>
+        <el-descriptions-item label="name"> {{accountInfo.name}} </el-descriptions-item>
+    </el-descriptions>
+</el-dialog>

'确定'按钮点击失效问题

image-20230219214203987

vue
<template>
+	<div class="text-update-wrap">
+		<p class="text-show" v-if="!isEditing">
+			<span
+				class="single-overflow text-val"
+				:style="{ 'max-width': maxWidth }"
+        :title="text"
+				>{{ text }}</span
+			>
+			<span class="el-icon-edit" @click="switchToEdit"></span>
+		</p>
+		<p class="text-edit" v-else>
+			<el-input
+				v-model="inputVal"
+				ref="inputRef"
+				:placeholder="'请输入' + name"
+				size="mini"
+				clearable
+			></el-input>
+       <!-- @blur='cancelUpdate' 事件比confirmUpdate先执行,导致确定按钮事件没触发-->
+			<span
+				title="确定"
+				:class="loading ? 'el-icon-loading' : 'el-icon-circle-check'"
+				@click="confirmUpdate"
+			></span>
+			<span
+				title="取消"
+				class="el-icon-circle-close"
+				@click="cancelEdit"
+				v-if="!loading"
+			></span>
+		</p>
+	</div>
+</template>
+
+<script>
+export default {
+	name: "UpdateText",
+	props: {
+		textVal: {
+			type: String,
+			default: "",
+		},
+		name: {
+			type: String,
+			default: "名称",
+		},
+		maxWidth: {
+			type: String,
+			default: "200px",
+		},
+    id: {
+      type: String,
+      default: "",
+    },
+	},
+	data() {
+		return {
+			loading: false,
+			isEditing: false,
+			inputVal: "",
+			text: this.textVal,
+		}
+	},
+	computed: {},
+	watch: {},
+	components: {},
+	methods: {
+		//切换到输入框模式
+		switchToEdit() {
+			this.inputVal = this.textVal
+			this.isEditing = true
+			this.$nextTick(() => {
+				this.$refs.inputRef.focus()
+			})
+		},
+    cancelEdit(){
+				this.isEditing = false	
+    },
+		//确定更新
+	   confirmUpdate() {
+			let { inputVal, name ,id} = this
+      let value = inputVal.trim()
+			if (value === "") {
+				this.$message.error(\`\${name}不能为空\`)
+				return
+			}else if(value === this.textVal){
+				this.isEditing = false
+				return
+			}
+			this.loading = true
+      if(id){
+        this.$emit("confirm", value, id)
+      }else{
+        this.$emit("confirm", value)
+      }
+		},
+		successUpdate() {
+      let { inputVal, name } = this
+			this.loading = false
+			this.text = inputVal
+			this.isEditing = false
+			this.$notify.success(\`\${name}修改成功\`)
+		},
+    //失败
+    failUpdate() {
+      this.loading = false
+      this.$notify.error(\`\${this.name}修改失败\`)
+    },
+	},
+	created() {},
+	mounted() {
+		//解决方案:不使用@blur, 监听焦点不在此组件时,才取消编辑
+		document.addEventListener("click", (e) => {
+			if (!this.$el.contains(e.target)) {
+				this.cancelEdit()
+			}
+		})
+	},
+}
+</script>
<template>
+	<div class="text-update-wrap">
+		<p class="text-show" v-if="!isEditing">
+			<span
+				class="single-overflow text-val"
+				:style="{ 'max-width': maxWidth }"
+        :title="text"
+				>{{ text }}</span
+			>
+			<span class="el-icon-edit" @click="switchToEdit"></span>
+		</p>
+		<p class="text-edit" v-else>
+			<el-input
+				v-model="inputVal"
+				ref="inputRef"
+				:placeholder="'请输入' + name"
+				size="mini"
+				clearable
+			></el-input>
+       <!-- @blur='cancelUpdate' 事件比confirmUpdate先执行,导致确定按钮事件没触发-->
+			<span
+				title="确定"
+				:class="loading ? 'el-icon-loading' : 'el-icon-circle-check'"
+				@click="confirmUpdate"
+			></span>
+			<span
+				title="取消"
+				class="el-icon-circle-close"
+				@click="cancelEdit"
+				v-if="!loading"
+			></span>
+		</p>
+	</div>
+</template>
+
+<script>
+export default {
+	name: "UpdateText",
+	props: {
+		textVal: {
+			type: String,
+			default: "",
+		},
+		name: {
+			type: String,
+			default: "名称",
+		},
+		maxWidth: {
+			type: String,
+			default: "200px",
+		},
+    id: {
+      type: String,
+      default: "",
+    },
+	},
+	data() {
+		return {
+			loading: false,
+			isEditing: false,
+			inputVal: "",
+			text: this.textVal,
+		}
+	},
+	computed: {},
+	watch: {},
+	components: {},
+	methods: {
+		//切换到输入框模式
+		switchToEdit() {
+			this.inputVal = this.textVal
+			this.isEditing = true
+			this.$nextTick(() => {
+				this.$refs.inputRef.focus()
+			})
+		},
+    cancelEdit(){
+				this.isEditing = false	
+    },
+		//确定更新
+	   confirmUpdate() {
+			let { inputVal, name ,id} = this
+      let value = inputVal.trim()
+			if (value === "") {
+				this.$message.error(\`\${name}不能为空\`)
+				return
+			}else if(value === this.textVal){
+				this.isEditing = false
+				return
+			}
+			this.loading = true
+      if(id){
+        this.$emit("confirm", value, id)
+      }else{
+        this.$emit("confirm", value)
+      }
+		},
+		successUpdate() {
+      let { inputVal, name } = this
+			this.loading = false
+			this.text = inputVal
+			this.isEditing = false
+			this.$notify.success(\`\${name}修改成功\`)
+		},
+    //失败
+    failUpdate() {
+      this.loading = false
+      this.$notify.error(\`\${this.name}修改失败\`)
+    },
+	},
+	created() {},
+	mounted() {
+		//解决方案:不使用@blur, 监听焦点不在此组件时,才取消编辑
+		document.addEventListener("click", (e) => {
+			if (!this.$el.contains(e.target)) {
+				this.cancelEdit()
+			}
+		})
+	},
+}
+</script>

文本溢出隐藏处理后对不齐问题

image-20230219214258711

css
.el-checkbox {
+  width: 200px;
+  ::v-deep .el-checkbox__label {
+    width: 186px;
+    vertical-align: middle; //需要重新设置对齐线
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}
.el-checkbox {
+  width: 200px;
+  ::v-deep .el-checkbox__label {
+    width: 186px;
+    vertical-align: middle; //需要重新设置对齐线
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}

路由组件切换,事件总线意外多次触发

js
//A路由组件
+this.$bus.$emit("searchDone")
//A路由组件
+this.$bus.$emit("searchDone")
js
//B路由组件
+mounted(){
+		this.$bus.$off('searchDone') //在每次绑定事件前,先解绑该事件
+
+		this.$bus.$on('searchDone',this.handleCurrentChange)
+	},
//B路由组件
+mounted(){
+		this.$bus.$off('searchDone') //在每次绑定事件前,先解绑该事件
+
+		this.$bus.$on('searchDone',this.handleCurrentChange)
+	},

前端配合 Nginx 服务开启 gzip 页面加载不出来

js
//vue.config.js
+plugins: [
+	new CompressionWebpackPlugin({
+		exclude: /node_modules/,
+		test: /\\.(js|css)$/,
+		threshold: 10240, // 超过10kb的文件就压缩
+		deleteOriginalAssets: true, // 不删除源文件
+		algorithm: "gzip",
+		minRatio: 0.8,
+	}),
+],
//vue.config.js
+plugins: [
+	new CompressionWebpackPlugin({
+		exclude: /node_modules/,
+		test: /\\.(js|css)$/,
+		threshold: 10240, // 超过10kb的文件就压缩
+		deleteOriginalAssets: true, // 不删除源文件
+		algorithm: "gzip",
+		minRatio: 0.8,
+	}),
+],

2023-03-30-14-58-50

TailwindCSS动态绑定类不能随着渐变

vue

+<template>
+  <header  :class="headerBg"></header>
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+//通过判断滚动的距离,来决定header 背景色的变化
+
+let headerBg = ref("bg-zinc-900/[.00]");
+const handleScroll = () => {
+  const scrollHeight = document.documentElement.scrollTop;
+  if (scrollHeight < 100) {
+    let opacity = (scrollHeight / 100).toFixed(1).slice(1);
+    headerBg.value = \`bg-zinc-900/[\${opacity}]\`
+  } else {
+    headerBg.value = \`bg-zinc-900/[1]\`
+  }
+};
+  window.addEventListener("scroll", handleScroll);
+</script>

+<template>
+  <header  :class="headerBg"></header>
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+//通过判断滚动的距离,来决定header 背景色的变化
+
+let headerBg = ref("bg-zinc-900/[.00]");
+const handleScroll = () => {
+  const scrollHeight = document.documentElement.scrollTop;
+  if (scrollHeight < 100) {
+    let opacity = (scrollHeight / 100).toFixed(1).slice(1);
+    headerBg.value = \`bg-zinc-900/[\${opacity}]\`
+  } else {
+    headerBg.value = \`bg-zinc-900/[1]\`
+  }
+};
+  window.addEventListener("scroll", handleScroll);
+</script>

监听非 window resize 事件不生效问题

不会生效原因: div 元素默认不会触发 resize 事件。在 window 对象上,浏览器会自动跟踪窗口的大小变化并触发 resize 事件,但在其他元素上,您需要自己编写代码来检测大小变化。可以使用 MutationObserver 或者 ResizeObserver 来监听元素大小变化。以下是使用 ResizeObserver 的示例代码:

js
mounted() {
+  this.tagListRef = this.$refs.tagListRef;
+  this.tagBoxRef = this.$refs.tagBoxRef;
+  this.resizeHandler()
+  
+  // 创建 ResizeObserver 实例
+  this.tagListResizeObserver = new ResizeObserver(this.resizeHandler);
+  // 监听 tagListRef 元素的大小变化
+  this.tagListResizeObserver.observe(this.tagListRef);
+  
+  this.tagListRef.addEventListener('wheel', this.handleScroll);
+},
+beforeUnmount() {
+  // 在组件卸载前,停止 ResizeObserver 实例
+  this.tagListResizeObserver.disconnect();
+},
+methods: {
+  handleScroll(e) {
+    e.preventDefault();
+    this.tagListRef.scrollLeft += e.deltaY * 100;
+  },
+  scrollHandler(direction) {
+    this.tagListRef.scrollLeft += direction * this.tagListWidth;
+  },
+  resizeHandler(entries) {
+    // entries 是 ResizeObserver 的回调参数,包含被观察的元素的信息
+    this.tagListWidth = this.tagListRef.clientWidth
+    this.tagBoxWidth = this.tagBoxRef.clientWidth
+  } 
+}
mounted() {
+  this.tagListRef = this.$refs.tagListRef;
+  this.tagBoxRef = this.$refs.tagBoxRef;
+  this.resizeHandler()
+  
+  // 创建 ResizeObserver 实例
+  this.tagListResizeObserver = new ResizeObserver(this.resizeHandler);
+  // 监听 tagListRef 元素的大小变化
+  this.tagListResizeObserver.observe(this.tagListRef);
+  
+  this.tagListRef.addEventListener('wheel', this.handleScroll);
+},
+beforeUnmount() {
+  // 在组件卸载前,停止 ResizeObserver 实例
+  this.tagListResizeObserver.disconnect();
+},
+methods: {
+  handleScroll(e) {
+    e.preventDefault();
+    this.tagListRef.scrollLeft += e.deltaY * 100;
+  },
+  scrollHandler(direction) {
+    this.tagListRef.scrollLeft += direction * this.tagListWidth;
+  },
+  resizeHandler(entries) {
+    // entries 是 ResizeObserver 的回调参数,包含被观察的元素的信息
+    this.tagListWidth = this.tagListRef.clientWidth
+    this.tagBoxWidth = this.tagBoxRef.clientWidth
+  } 
+}
`,24),t=[o];function e(c,r,y,A,D,i){return n(),a("div",null,t)}const C=s(p,[["render",e]]);export{E as __pageData,C as default}; diff --git "a/assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.lean.js" "b/assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.lean.js" new file mode 100644 index 00000000..1a474d30 --- /dev/null +++ "b/assets/Problem_VueProject_Vue\351\241\271\347\233\256\350\270\251\345\235\221\344\270\200.md.5d32b46a.lean.js" @@ -0,0 +1 @@ +import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.c53372a0.js";const E=JSON.parse('{"title":"Vue项目踩坑一","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/VueProject/Vue项目踩坑一.md","filePath":"Problem/VueProject/Vue项目踩坑一.md"}'),p={name:"Problem/VueProject/Vue项目踩坑一.md"},o=l("",24),t=[o];function e(c,r,y,A,D,i){return n(),a("div",null,t)}const C=s(p,[["render",e]]);export{E as __pageData,C as default}; diff --git a/assets/Problem_index.md.724652c6.js b/assets/Problem_index.md.724652c6.js new file mode 100644 index 00000000..d55eafa6 --- /dev/null +++ b/assets/Problem_index.md.724652c6.js @@ -0,0 +1 @@ +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.c53372a0.js";const u=JSON.parse('{"title":"编程踩坑积累与总结","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/index.md","filePath":"Problem/index.md"}'),c={name:"Problem/index.md"},r=e("h1",{id:"编程踩坑积累与总结",tabindex:"-1"},[s("编程踩坑积累与总结 "),e("a",{class:"header-anchor",href:"#编程踩坑积累与总结","aria-label":'Permalink to "编程踩坑积累与总结"'},"​")],-1),n=e("div",{class:"tip custom-block"},[e("p",{class:"custom-block-title"},"TIP"),e("p",null,"这里主要记录编程遇到的问题,已经解决方案,以便以后回顾或找到更优解!")],-1),i=[r,n];function d(l,_,m,p,h,f){return a(),o("div",null,i)}const b=t(c,[["render",d]]);export{u as __pageData,b as default}; diff --git a/assets/Problem_index.md.724652c6.lean.js b/assets/Problem_index.md.724652c6.lean.js new file mode 100644 index 00000000..d55eafa6 --- /dev/null +++ b/assets/Problem_index.md.724652c6.lean.js @@ -0,0 +1 @@ +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.c53372a0.js";const u=JSON.parse('{"title":"编程踩坑积累与总结","description":"","frontmatter":{},"headers":[],"relativePath":"Problem/index.md","filePath":"Problem/index.md"}'),c={name:"Problem/index.md"},r=e("h1",{id:"编程踩坑积累与总结",tabindex:"-1"},[s("编程踩坑积累与总结 "),e("a",{class:"header-anchor",href:"#编程踩坑积累与总结","aria-label":'Permalink to "编程踩坑积累与总结"'},"​")],-1),n=e("div",{class:"tip custom-block"},[e("p",{class:"custom-block-title"},"TIP"),e("p",null,"这里主要记录编程遇到的问题,已经解决方案,以便以后回顾或找到更优解!")],-1),i=[r,n];function d(l,_,m,p,h,f){return a(),o("div",null,i)}const b=t(c,[["render",d]]);export{u as __pageData,b as default}; diff --git a/assets/app.c5d8d5ce.js b/assets/app.c5d8d5ce.js new file mode 100644 index 00000000..704d5215 --- /dev/null +++ b/assets/app.c5d8d5ce.js @@ -0,0 +1 @@ +import{d as c,u,Z as m,o as f,b as h,l as v,O as g,aa as s,s as i,ab as w,ac as _,ad as y,ae as A,af as P,ag as x,ah as b,ai as C,aj as D,ak as T,X as $,j as E,y as R,al as L,am as M,an as S}from"./chunks/framework.c53372a0.js";import{t as l}from"./chunks/theme.1e9d2528.js";import{D as j}from"./chunks/DemoWrap.1b6e7adf.js";const k=c({__name:"UnoCSSLayout",setup(a){const{isDark:e}=u();function t(){return"startViewTransition"in document&&window.matchMedia("(prefers-reduced-motion: no-preference)").matches}return m("toggle-appearance",async({clientX:n,clientY:o})=>{if(!t()){e.value=!e.value;return}const p=[`circle(0px at ${n}px ${o}px)`,`circle(${Math.hypot(Math.max(n,innerWidth-n),Math.max(o,innerHeight-o))}px at ${n}px ${o}px)`];await document.startViewTransition(async()=>{e.value=!e.value,await g()}).ready,document.documentElement.animate({clipPath:e.value?p.reverse():p},{duration:300,easing:"ease-in",pseudoElement:`::view-transition-${e.value?"old":"new"}(root)`})}),(n,o)=>(f(),h(v(l).Layout))}}),O={...l,Layout:()=>s(k,null,{"layout-bottom":()=>s(ReloadPrompt)}),enhanceApp(a){a.app.component("DemoWrap",j)}};function d(a){if(a.extends){const e=d(a.extends);return{...e,...a,async enhanceApp(t){e.enhanceApp&&await e.enhanceApp(t),a.enhanceApp&&await a.enhanceApp(t)}}}return a}const r=d(O),V=c({name:"VitePressApp",setup(){const{site:a}=u();return E(()=>{R(()=>{document.documentElement.lang=a.value.lang,document.documentElement.dir=a.value.dir})}),L(),M(),S(),r.setup&&r.setup(),()=>s(r.Layout)}});async function B(){const a=W(),e=F();e.provide(_,a);const t=y(a.route);return e.provide(A,t),e.component("Content",P),e.component("ClientOnly",x),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),r.enhanceApp&&await r.enhanceApp({app:e,router:a,siteData:b}),{app:e,router:a,data:t}}function F(){return C(V)}function W(){let a=i,e;return D(t=>{let n=T(t),o=null;return n&&(a&&(e=n),(a||e===n)&&(n=n.replace(/\.js$/,".lean.js")),o=$(()=>import(n),[])),i&&(a=!1),o},r.NotFound)}i&&B().then(({app:a,router:e,data:t})=>{e.go().then(()=>{w(e.route,t.site),a.mount("#app")})});export{B as createApp}; diff --git a/assets/chunks/@localSearchIndexroot.20abec5d.js b/assets/chunks/@localSearchIndexroot.20abec5d.js new file mode 100644 index 00000000..59754eb2 --- /dev/null +++ b/assets/chunks/@localSearchIndexroot.20abec5d.js @@ -0,0 +1 @@ +const t='{"documentCount":617,"nextId":617,"documentIds":{"0":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#一、相关概念","1":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#二、数据库操作","2":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#三、集合相关操作","3":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#四、文档相关操作","4":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_1-查询","5":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_2-插入","6":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_3-删除","7":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_4-更新","8":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#五、mongoose学习","9":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_1-插入","10":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_2-删除","11":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_3-更新","12":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_4-查询","13":"/zerdocs/BackEnd/NodeJS/MongoDB笔记#_5-模型","14":"/zerdocs/BackEnd/NodeJS/Node大文件上传#node大文件上传","15":"/zerdocs/BackEnd/NodeJS/Node大文件上传#vue-前端代码","16":"/zerdocs/BackEnd/NodeJS/Node学习笔记#一、读取文件","17":"/zerdocs/BackEnd/NodeJS/Node学习笔记#path-路径模块","18":"/zerdocs/BackEnd/NodeJS/Node学习笔记#二、写入文件","19":"/zerdocs/BackEnd/NodeJS/Node学习笔记#三、服务器操作","20":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_1-创建-web-服务器步骤","21":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_2-动态响应内容","22":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_3-响应文件内容","23":"/zerdocs/BackEnd/NodeJS/Node学习笔记#四、node-模块化","24":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_1-module-对象","25":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_2-模块共享","26":"/zerdocs/BackEnd/NodeJS/Node学习笔记#五、模块加载机制","27":"/zerdocs/BackEnd/NodeJS/Node学习笔记#六、express-模块","28":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_1-express-创建服务器","29":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_2-express-中间件","30":"/zerdocs/BackEnd/NodeJS/Node学习笔记#七、编写接口","31":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_1-cors-跨域资源共享","32":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_2-cors-头部","33":"/zerdocs/BackEnd/NodeJS/Node学习笔记#八、node-连接数据库","34":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_1-配置-mysql-模块","35":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_2-查询数据","36":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_3-插入数据","37":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_4-更新数据","38":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_5-删除数据","39":"/zerdocs/BackEnd/NodeJS/Node学习笔记#九、身份认证","40":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_1-http-协议的特性","41":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_2-cookie-特性","42":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_3-session-认证","43":"/zerdocs/BackEnd/NodeJS/Node学习笔记#_4-jwt-认证","44":"/zerdocs/BackEnd/NodeJS/Node简单上传文件#node-简单上传文件","45":"/zerdocs/BackEnd/NodeJS/Node简单上传文件#vue-前端代码","46":"/zerdocs/BackEnd/NodeJS/Node简单上传文件#express-后端代码","47":"/zerdocs/BackEnd/Server/Docker学习笔记#一、解决痛点","48":"/zerdocs/BackEnd/Server/Docker学习笔记#二、优点和应用","49":"/zerdocs/BackEnd/Server/Docker学习笔记#三、基本组成","50":"/zerdocs/BackEnd/Server/Docker学习笔记#四、工作原理","51":"/zerdocs/BackEnd/Server/Docker学习笔记#五、centos安装docker","52":"/zerdocs/BackEnd/Server/Docker学习笔记#六、阿里云镜像加速","53":"/zerdocs/BackEnd/Server/Docker学习笔记#七、常用命令","54":"/zerdocs/BackEnd/Server/Docker学习笔记#_1-docker","55":"/zerdocs/BackEnd/Server/Docker学习笔记#_2-镜像","56":"/zerdocs/BackEnd/Server/Docker学习笔记#_3-容器","57":"/zerdocs/BackEnd/Server/Docker学习笔记#启动守护式","58":"/zerdocs/BackEnd/Server/Docker学习笔记#查看容器日志","59":"/zerdocs/BackEnd/Server/Docker学习笔记#容器备份到主机","60":"/zerdocs/BackEnd/Server/Docker学习笔记#容器卷","61":"/zerdocs/BackEnd/Server/Docker学习笔记#八、dockerfile编写","62":"/zerdocs/BackEnd/Server/Docker学习笔记#九、docker网络","63":"/zerdocs/BackEnd/Server/Docker学习笔记#共用网卡","64":"/zerdocs/BackEnd/Server/Docker学习笔记#自定义网络","65":"/zerdocs/BackEnd/Server/Docker学习笔记#十、容器编排","66":"/zerdocs/BackEnd/Server/Docker学习笔记#_1-安装compose","67":"/zerdocs/BackEnd/Server/Docker学习笔记#_2-常用命令","68":"/zerdocs/BackEnd/Server/Docker学习笔记#_3-安装-portainer","69":"/zerdocs/BackEnd/Server/Nginx学习笔记#一、nginx安装","70":"/zerdocs/BackEnd/Server/Nginx学习笔记#_1-安装命令","71":"/zerdocs/BackEnd/Server/Nginx学习笔记#_2-linux目录结构","72":"/zerdocs/BackEnd/Server/Nginx学习笔记#_3-基础命令","73":"/zerdocs/BackEnd/Server/Nginx学习笔记#编写配置","74":"/zerdocs/BackEnd/Server/Nginx学习笔记#日志分析器","75":"/zerdocs/BackEnd/Server/Nginx学习笔记#centos7联网","76":"/zerdocs/Framework/Angular/Angular基础总结一#angular基础总结一","77":"/zerdocs/Framework/Angular/Angular基础总结一#一、ngmodule","78":"/zerdocs/Framework/Angular/Angular基础总结一#ngmodule元数据","79":"/zerdocs/Framework/Angular/Angular基础总结一#declarations-数组","80":"/zerdocs/Framework/Angular/Angular基础总结一#imports-数组","81":"/zerdocs/Framework/Angular/Angular基础总结一#providers-数组","82":"/zerdocs/Framework/Angular/Angular基础总结一#bootstrap-数组","83":"/zerdocs/Framework/Angular/Angular基础总结一#二、模板基础语法","84":"/zerdocs/Framework/Angular/Angular基础总结一#_1-模板表达式","85":"/zerdocs/Framework/Angular/Angular基础总结一#_2-模板来源","86":"/zerdocs/Framework/Angular/Angular基础总结一#_3-属性绑定","87":"/zerdocs/Framework/Angular/Angular基础总结一#_4-自定义属性绑定","88":"/zerdocs/Framework/Angular/Angular基础总结一#_5-插值表达式属性绑定","89":"/zerdocs/Framework/Angular/Angular基础总结一#_6-单个class样式绑定","90":"/zerdocs/Framework/Angular/Angular基础总结一#_7-绑定多个class","91":"/zerdocs/Framework/Angular/Angular基础总结一#_8-绑定单个style","92":"/zerdocs/Framework/Angular/Angular基础总结一#_9-绑定多个style","93":"/zerdocs/Framework/Angular/Angular基础总结一#_10-绑定事件","94":"/zerdocs/Framework/Angular/Angular基础总结一#_11-输入与输出属性","95":"/zerdocs/Framework/Angular/Angular基础总结一#输入属性-input","96":"/zerdocs/Framework/Angular/Angular基础总结一#输出属性-output","97":"/zerdocs/Framework/Angular/Angular基础总结一#三、组件样式","98":"/zerdocs/Framework/Angular/Angular基础总结一#宿主选择器","99":"/zerdocs/Framework/Angular/Angular基础总结一#祖先选择器","100":"/zerdocs/Framework/Angular/Angular基础总结一#样式模块化","101":"/zerdocs/Framework/Angular/Angular基础总结一#视图封装模式","102":"/zerdocs/Framework/Angular/Angular基础总结三#组件投影","103":"/zerdocs/Framework/Angular/Angular基础总结三#viewchild","104":"/zerdocs/Framework/Angular/Angular基础总结三#viewchildren","105":"/zerdocs/Framework/Angular/Angular基础总结三#contentchild","106":"/zerdocs/Framework/Angular/Angular基础总结三#contentchildren","107":"/zerdocs/Framework/Angular/Angular基础总结三#自定义管道","108":"/zerdocs/Framework/Angular/Angular基础总结三#非纯管道","109":"/zerdocs/Framework/Angular/Angular基础总结三#生命周期","110":"/zerdocs/Framework/Angular/Angular基础总结三#变更检测","111":"/zerdocs/Framework/Angular/Angular基础总结三#默认策略下触发变更检测的时机","112":"/zerdocs/Framework/Angular/Angular基础总结三#onpush下触发变更检测时机","113":"/zerdocs/Framework/Angular/Angular基础总结三#动态组件","114":"/zerdocs/Framework/Angular/Angular基础总结三#ngtemplateoutlet指令","115":"/zerdocs/Framework/Angular/Angular基础总结二#双向绑定","116":"/zerdocs/Framework/Angular/Angular基础总结二#_1-基本双向绑定","117":"/zerdocs/Framework/Angular/Angular基础总结二#_2-input双向绑定","118":"/zerdocs/Framework/Angular/Angular基础总结二#_3-表单form中双向绑定","119":"/zerdocs/Framework/Angular/Angular基础总结二#属性型指令","120":"/zerdocs/Framework/Angular/Angular基础总结二#结构型指令","121":"/zerdocs/Framework/Angular/Angular基础总结二#ngif指令","122":"/zerdocs/Framework/Angular/Angular基础总结二#ngfor指令","123":"/zerdocs/Framework/Angular/Angular基础总结二#ngswitch-指令","124":"/zerdocs/Framework/Angular/Angular基础总结二#自定义指令","125":"/zerdocs/Framework/Angular/Angular基础总结二#自定义高亮指令-属性型","126":"/zerdocs/Framework/Angular/Angular基础总结二#自定义unless指令-结构型","127":"/zerdocs/Framework/Angular/Angular基础总结二#模板元素","128":"/zerdocs/Framework/Angular/Angular基础总结二#ng-template","129":"/zerdocs/Framework/Angular/Angular基础总结二#ng-container","130":"/zerdocs/Framework/Angular/Angular基础总结二#模板引用变量","131":"/zerdocs/Framework/Angular/Angular基础总结二#操作符","132":"/zerdocs/Framework/Angular/Angular基础总结二#管道","133":"/zerdocs/Framework/Angular/Angular基础总结二#安全链","134":"/zerdocs/Framework/Angular/Angular基础总结二#非空断言","135":"/zerdocs/Framework/Angular/Angular基础总结二#类型转换函数-any","136":"/zerdocs/Framework/React/React基础总结一#一、前置知识","137":"/zerdocs/Framework/React/React基础总结一#虚拟dom","138":"/zerdocs/Framework/React/React基础总结一#二、组件","139":"/zerdocs/Framework/React/React基础总结一#函数式组件","140":"/zerdocs/Framework/React/React基础总结一#类式组件","141":"/zerdocs/Framework/React/React基础总结一#补充","142":"/zerdocs/Framework/React/React基础总结一#组实例三大属性","143":"/zerdocs/Framework/React/React基础总结一#state","144":"/zerdocs/Framework/React/React基础总结一#props","145":"/zerdocs/Framework/React/React基础总结一#refs","146":"/zerdocs/Framework/React/React基础总结一#事件处理","147":"/zerdocs/Framework/React/React基础总结一#组件生命周期","148":"/zerdocs/Framework/Vue/Vite原理学习#vite底层原理学习","149":"/zerdocs/Framework/Vue/Vite原理学习#构建工具承担","150":"/zerdocs/Framework/Vue/Vue3补漏笔记#inheritattrs","151":"/zerdocs/Framework/Vue/Vue3补漏笔记#场景一","152":"/zerdocs/Framework/Vue/Vue3补漏笔记#场景二","153":"/zerdocs/Framework/Vue/Vue3补漏笔记#场景三","154":"/zerdocs/Framework/Vue/分页与搜索条件记录并回显优化#分页与搜索条件记录并回显优化","155":"/zerdocs/Framework/Vue/分页与搜索条件记录并回显优化#整体逻辑","156":"/zerdocs/Framework/Vue/分页与搜索条件记录并回显优化#store","157":"/zerdocs/Framework/Vue/分页与搜索条件记录并回显优化#mixins","158":"/zerdocs/Framework/Vue/分页与搜索条件记录并回显优化#列表页-xxxlist-vue","159":"/zerdocs/Framework/Vue/列表最后一条数据删除处理#一、删除最后一条数据跳转到上一页","160":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#grid布局学习笔记","161":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#实用网站","162":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#基本概念","163":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#容器属性","164":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#开启-grid布局","165":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#容器划分行列","166":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#调整间距属性","167":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#容器内网格对齐方式","168":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#网格内项目对其方式","169":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#项目排列顺序","170":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#容器中区域定义","171":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#项目属性","172":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#合并单元格属性","173":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#项目区域定义","174":"/zerdocs/FrontEnd/CSS/Grid布局学习笔记#单个项目位置","175":"/zerdocs/FrontEnd/CSS/常用代码段#css常用代码段","176":"/zerdocs/FrontEnd/CSS/常用代码段#单行与多行溢出隐藏","177":"/zerdocs/FrontEnd/CSS/常用代码段#自定义滚动条","178":"/zerdocs/FrontEnd/CSS/常用代码段#画布网状满天星背景","179":"/zerdocs/FrontEnd/CSS/常用代码段#轮播闪光","180":"/zerdocs/FrontEnd/CSS/常用代码段#flex布局子元素给了高度-实际渲染确有小数点问题","181":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#妙妙怪的《css-揭秘》读书摘要","182":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#背景与边框","183":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#多重边框","184":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#灵活的背景定位","185":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#边框内圆角","186":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#条纹背景","187":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#形状","188":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#圆角","189":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#平行四边形","190":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#梯形","191":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#视觉效果","192":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#双侧投影","193":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#染色效果","194":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#毛玻璃","195":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#折角效果","196":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#字体排印","197":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#插入换行","198":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#文本行斑马线","199":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#自定义下划线","200":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#凹凸印刷文字效果","201":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#满幅背景、定宽内容-页脚","202":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#紧贴底部的页脚","203":"/zerdocs/FrontEnd/CSS/揭秘读书摘要#闪烁效果","204":"/zerdocs/FrontEnd/Git/Git常用操作#git常用操作","205":"/zerdocs/FrontEnd/Git/Git常用操作#拉取最新提交","206":"/zerdocs/FrontEnd/Git/Git常用操作#删除远程分支","207":"/zerdocs/FrontEnd/Git/Git常用操作#删除tag","208":"/zerdocs/FrontEnd/Git/Git常用操作#删除远程文件","209":"/zerdocs/FrontEnd/Git/Git常用操作#fork后的仓库-拉取合并原仓库的更新","210":"/zerdocs/FrontEnd/Git/Git常用操作#合并多次提交","211":"/zerdocs/FrontEnd/Git/Git常用操作#关联多个代码托管平台","212":"/zerdocs/FrontEnd/Git/Git常用操作#改错分支但为未提交","213":"/zerdocs/FrontEnd/Git/Git常用操作#提交完未推送前-需要再次提交","214":"/zerdocs/FrontEnd/Git/Git常用操作#修改第一次提交信息","215":"/zerdocs/FrontEnd/Git/Git常用操作#代码提交到了错误的分支","216":"/zerdocs/FrontEnd/Git/Git常用操作#方法一","217":"/zerdocs/FrontEnd/Git/Git常用操作#方法二","218":"/zerdocs/FrontEnd/Git/Git常用操作#git-提交规范化","219":"/zerdocs/FrontEnd/Git/Git常用操作#注意-需要-git-init后才能初始化-否则报错如下","220":"/zerdocs/FrontEnd/Git/Git常用操作#commitlint-cli与-commitlint-config-conventional","221":"/zerdocs/FrontEnd/Git/Git常用操作#cz-conventional-changelog","222":"/zerdocs/FrontEnd/Git/Terminal终端美化#安装oh-my-posh","223":"/zerdocs/FrontEnd/Git/Terminal终端美化#预览所有主题命令","224":"/zerdocs/FrontEnd/Git/Terminal终端美化#初始化并应用主题","225":"/zerdocs/FrontEnd/Git/Terminal终端美化#分隔符乱码问题","226":"/zerdocs/FrontEnd/Git/Terminal终端美化#配置powershell","227":"/zerdocs/FrontEnd/Git/Terminal终端美化#_1-打开配置文件方式一","228":"/zerdocs/FrontEnd/Git/Terminal终端美化#_2-打开配置文件方式二","229":"/zerdocs/FrontEnd/Git/Terminal终端美化#自定义主题","230":"/zerdocs/FrontEnd/Git/Terminal终端美化#vs-code终端配置","231":"/zerdocs/FrontEnd/Git/Terminal终端美化#隐藏提示语","232":"/zerdocs/FrontEnd/Git/配置多个平台SSH#_1-生成公钥和私钥","233":"/zerdocs/FrontEnd/Git/配置多个平台SSH#_2-在代码托管平台设置添加公钥","234":"/zerdocs/FrontEnd/Git/配置多个平台SSH#_3-添加私钥到ssh-agent中","235":"/zerdocs/FrontEnd/Git/配置多个平台SSH#_4-创建config件-打开编辑","236":"/zerdocs/FrontEnd/Git/配置多个平台SSH#ssh公钥私钥加密解密原理","237":"/zerdocs/FrontEnd/JavaScript/async与await#javascript实现异步","238":"/zerdocs/FrontEnd/JavaScript/async与await#方式一-回调函数","239":"/zerdocs/FrontEnd/JavaScript/async与await#方式二-promise","240":"/zerdocs/FrontEnd/JavaScript/async与await#语法糖-async-await","241":"/zerdocs/FrontEnd/JavaScript/async与await#实现fn1先执行","242":"/zerdocs/FrontEnd/JavaScript/async与await#捕获异常","243":"/zerdocs/FrontEnd/JavaScript/async与await#使用陷阱","244":"/zerdocs/FrontEnd/JavaScript/代码分支优化#if-else-多分支优化","245":"/zerdocs/FrontEnd/JavaScript/代码分支优化#简单分支","246":"/zerdocs/FrontEnd/JavaScript/代码分支优化#条件单一-处理不同","247":"/zerdocs/FrontEnd/JavaScript/代码分支优化#条件复杂-处理也复杂","248":"/zerdocs/FrontEnd/JavaScript/图片懒加载#js-图片懒加载","249":"/zerdocs/FrontEnd/JavaScript/图片懒加载#方案一-监听滚动","250":"/zerdocs/FrontEnd/JavaScript/图片懒加载#方案二-观察者","251":"/zerdocs/FrontEnd/JavaScript/基础复习一#_1-算术运算符","252":"/zerdocs/FrontEnd/JavaScript/基础复习一#_2-赋值运算符","253":"/zerdocs/FrontEnd/JavaScript/基础复习一#_3-运算符","254":"/zerdocs/FrontEnd/JavaScript/基础复习一#_4-自增和自减","255":"/zerdocs/FrontEnd/JavaScript/基础复习一#_5-逻辑运算符","256":"/zerdocs/FrontEnd/JavaScript/基础复习一#_6-关系运算符","257":"/zerdocs/FrontEnd/JavaScript/基础复习一#_7-相等运算符","258":"/zerdocs/FrontEnd/JavaScript/基础复习一#_8-条件运算符","259":"/zerdocs/FrontEnd/JavaScript/基础复习一#_9-控制语句","260":"/zerdocs/FrontEnd/JavaScript/基础复习一#_10-循环语句","261":"/zerdocs/FrontEnd/JavaScript/基础复习一#_11-数据类型","262":"/zerdocs/FrontEnd/JavaScript/基础复习二#this指向","263":"/zerdocs/FrontEnd/JavaScript/基础复习二#可变参数-arguments","264":"/zerdocs/FrontEnd/JavaScript/基础复习二#剩余参数-args","265":"/zerdocs/FrontEnd/JavaScript/基础复习二#map","266":"/zerdocs/FrontEnd/JavaScript/基础复习二#set","267":"/zerdocs/FrontEnd/JavaScript/基础复习二#随机数生成","268":"/zerdocs/FrontEnd/JavaScript/基础复习二#时间格式化","269":"/zerdocs/FrontEnd/JavaScript/基础复习二#面向对象之类","270":"/zerdocs/FrontEnd/JavaScript/基础复习二#封装","271":"/zerdocs/FrontEnd/JavaScript/基础复习二#继承","272":"/zerdocs/FrontEnd/JavaScript/基础复习二#多态","273":"/zerdocs/FrontEnd/JavaScript/基础复习二#对象的结构","274":"/zerdocs/FrontEnd/JavaScript/基础复习二#原型","275":"/zerdocs/FrontEnd/JavaScript/基础复习二#原型链","276":"/zerdocs/FrontEnd/JavaScript/基础复习二#修改原型","277":"/zerdocs/FrontEnd/JavaScript/基础复习二#instanceof-in-hasown","278":"/zerdocs/FrontEnd/JavaScript/基础复习二#_10-new运算符","279":"/zerdocs/FrontEnd/JavaScript/常见算法#括号匹配","280":"/zerdocs/FrontEnd/JavaScript/常见算法#简单递归","281":"/zerdocs/FrontEnd/JavaScript/常见算法#计算阶乘","282":"/zerdocs/FrontEnd/JavaScript/常见算法#扁平化数组","283":"/zerdocs/FrontEnd/JavaScript/常见算法#反转字符串","284":"/zerdocs/FrontEnd/JavaScript/常见算法#求最大公约数","285":"/zerdocs/FrontEnd/JavaScript/常见算法#斐波那契数列","286":"/zerdocs/FrontEnd/JavaScript/常见算法#排序算法","287":"/zerdocs/FrontEnd/JavaScript/常见算法#冒泡排序","288":"/zerdocs/FrontEnd/JavaScript/常见算法#选择排序","289":"/zerdocs/FrontEnd/JavaScript/常见算法#快速排序","290":"/zerdocs/FrontEnd/JavaScript/常见算法#插入排序","291":"/zerdocs/FrontEnd/JavaScript/常见算法#希尔排序","292":"/zerdocs/FrontEnd/JavaScript/常见算法#求两个有序数组的中位数","293":"/zerdocs/FrontEnd/JavaScript/常见算法#实现eventemitter","294":"/zerdocs/FrontEnd/JavaScript/常见算法#返回给定起止字符串月份中间所有月份","295":"/zerdocs/FrontEnd/JavaScript/常见算法#实现promise的all方法","296":"/zerdocs/FrontEnd/JavaScript/常见算法#lru缓存算法","297":"/zerdocs/FrontEnd/JavaScript/常见算法#不使用乘法符号乘法函数","298":"/zerdocs/FrontEnd/JavaScript/常见算法#链表反转","299":"/zerdocs/FrontEnd/JavaScript/常见算法#二叉树的遍历","300":"/zerdocs/FrontEnd/JavaScript/常见算法#二叉搜索树的插入和查找","301":"/zerdocs/FrontEnd/JavaScript/常见算法#字符串搜索算法","302":"/zerdocs/FrontEnd/JavaScript/常见算法#数字转中文","303":"/zerdocs/FrontEnd/JavaScript/手写Promise#一、声名promise并绑定this","304":"/zerdocs/FrontEnd/JavaScript/手写Promise#二、状态保护与执行者异步捕获","305":"/zerdocs/FrontEnd/JavaScript/手写Promise#三、then方法构建","306":"/zerdocs/FrontEnd/JavaScript/手写Promise#四、实现then异步","307":"/zerdocs/FrontEnd/JavaScript/手写Promise#五、解决同步代码需要等待执行问题","308":"/zerdocs/FrontEnd/JavaScript/手写Promise#六、then的链式操作","309":"/zerdocs/FrontEnd/JavaScript/手写Promise#七、返回值的判断与处理","310":"/zerdocs/FrontEnd/JavaScript/手写Promise#八、代码优化及复用","311":"/zerdocs/FrontEnd/JavaScript/手写Promise#九、返回类型约束","312":"/zerdocs/FrontEnd/JavaScript/手写Promise#十、实现resolve和reject","313":"/zerdocs/FrontEnd/JavaScript/手写Promise#十一、promise-all-实现","314":"/zerdocs/FrontEnd/JavaScript/手写Promise#十二、实现promise-race","315":"/zerdocs/FrontEnd/JavaScript/手写Promise#十三、完整代码","316":"/zerdocs/FrontEnd/JavaScript/数据去重#基本数据类型","317":"/zerdocs/FrontEnd/JavaScript/数据去重#对象数组去重","318":"/zerdocs/FrontEnd/JavaScript/数据去重#对象相同比较","319":"/zerdocs/FrontEnd/JavaScript/数据去重#对象数组去重-1","320":"/zerdocs/FrontEnd/JavaScript/数组求集合#js常用的求交集、并集、差集的方法","321":"/zerdocs/FrontEnd/JavaScript/数组求集合#普通数组","322":"/zerdocs/FrontEnd/JavaScript/数组求集合#一、并集-a∪b","323":"/zerdocs/FrontEnd/JavaScript/数组求集合#二、交集-a∩b","324":"/zerdocs/FrontEnd/JavaScript/数组求集合#三、差集-a-b","325":"/zerdocs/FrontEnd/JavaScript/数组求集合#对象数组","326":"/zerdocs/FrontEnd/JavaScript/数组求集合#一、并集-a∪b-1","327":"/zerdocs/FrontEnd/JavaScript/数组求集合#二、交集-a∩b-1","328":"/zerdocs/FrontEnd/JavaScript/数组求集合#三、差集-a-b-1","329":"/zerdocs/FrontEnd/JavaScript/文件系统#blob与-file","330":"/zerdocs/FrontEnd/JavaScript/文件系统#arraybuffer","331":"/zerdocs/FrontEnd/JavaScript/文件系统#filereader","332":"/zerdocs/FrontEnd/JavaScript/文件系统#dataview","333":"/zerdocs/FrontEnd/JavaScript/文件系统#filepicker","334":"/zerdocs/FrontEnd/JavaScript/文件系统#文件操作","335":"/zerdocs/FrontEnd/JavaScript/文件系统#url","336":"/zerdocs/FrontEnd/JavaScript/文件系统#参考资料","337":"/zerdocs/FrontEnd/JavaScript/正则表达式#资料参考-learnregex","338":"/zerdocs/FrontEnd/JavaScript/正则表达式#应用场景","339":"/zerdocs/FrontEnd/JavaScript/正则表达式#可视化工具","340":"/zerdocs/FrontEnd/JavaScript/正则表达式#_1-或者","341":"/zerdocs/FrontEnd/JavaScript/正则表达式#_2-原子表-、原子组","342":"/zerdocs/FrontEnd/JavaScript/正则表达式#_3-边界符-、","343":"/zerdocs/FrontEnd/JavaScript/正则表达式#_4-元字符","344":"/zerdocs/FrontEnd/JavaScript/正则表达式#_5-匹配所有字符","345":"/zerdocs/FrontEnd/JavaScript/正则表达式#_6-模式修正符号i、g","346":"/zerdocs/FrontEnd/JavaScript/正则表达式#_7-原子组中的原子表","347":"/zerdocs/FrontEnd/JavaScript/正则表达式#_8-贪婪匹配-、-、","348":"/zerdocs/FrontEnd/JavaScript/正则表达式#批量验证密码","349":"/zerdocs/FrontEnd/JavaScript/正则表达式#_9-matchall","350":"/zerdocs/FrontEnd/JavaScript/正则表达式#_10-断言匹配","351":"/zerdocs/FrontEnd/JavaScript/正则表达式#将链接替换为想要的网址","352":"/zerdocs/FrontEnd/JavaScript/正则表达式#将不含oss的替换","353":"/zerdocs/FrontEnd/JavaScript/正则表达式#模糊电话后四位","354":"/zerdocs/FrontEnd/JavaScript/正则表达式#案例练习","355":"/zerdocs/FrontEnd/JavaScript/正则表达式#替换练习","356":"/zerdocs/FrontEnd/JavaScript/正则表达式#给原子组起别名","357":"/zerdocs/FrontEnd/JavaScript/获取目录结构#获取目录结构-纯前端","358":"/zerdocs/FrontEnd/JavaScript/高阶函数#高阶函数之filter","359":"/zerdocs/FrontEnd/JavaScript/高阶函数#定义","360":"/zerdocs/FrontEnd/JavaScript/高阶函数#语法","361":"/zerdocs/FrontEnd/JavaScript/高阶函数#用法","362":"/zerdocs/FrontEnd/JavaScript/高阶函数#过滤小于-100","363":"/zerdocs/FrontEnd/JavaScript/高阶函数#返回奇数元素","364":"/zerdocs/FrontEnd/JavaScript/高阶函数#数组去重","365":"/zerdocs/FrontEnd/JavaScript/高阶函数#找出素数","366":"/zerdocs/FrontEnd/JavaScript/高阶函数#高阶函数之map","367":"/zerdocs/FrontEnd/JavaScript/高阶函数#定义-1","368":"/zerdocs/FrontEnd/JavaScript/高阶函数#语法-1","369":"/zerdocs/FrontEnd/JavaScript/高阶函数#用法-1","370":"/zerdocs/FrontEnd/JavaScript/高阶函数#返回数组元素平方后的新数组","371":"/zerdocs/FrontEnd/JavaScript/高阶函数#用给定函数创建新字符串","372":"/zerdocs/FrontEnd/JavaScript/高阶函数#把二维数组变字符串","373":"/zerdocs/FrontEnd/JavaScript/高阶函数#数字序列转为数组-删除符号","374":"/zerdocs/FrontEnd/JavaScript/高阶函数#拿到所有图片的图片名称并以数组形式返回","375":"/zerdocs/FrontEnd/JavaScript/高阶函数#vue中循环注册组件","376":"/zerdocs/FrontEnd/JavaScript/高阶函数#高阶函数之-reduce","377":"/zerdocs/FrontEnd/JavaScript/高阶函数#定义-2","378":"/zerdocs/FrontEnd/JavaScript/高阶函数#语法-2","379":"/zerdocs/FrontEnd/JavaScript/高阶函数#用法-2","380":"/zerdocs/FrontEnd/JavaScript/高阶函数#数组求和","381":"/zerdocs/FrontEnd/JavaScript/高阶函数#数组去重-1","382":"/zerdocs/FrontEnd/JavaScript/高阶函数#计算两个或多个数字的平均值","383":"/zerdocs/FrontEnd/JavaScript/高阶函数#将多维数组转化为一维","384":"/zerdocs/FrontEnd/JavaScript/高阶函数#对象里的属性求和","385":"/zerdocs/FrontEnd/JavaScript/高阶函数#统计数组中每个元素出现的次数","386":"/zerdocs/FrontEnd/JavaScript/高阶函数#高阶函数之-sort","387":"/zerdocs/FrontEnd/JavaScript/高阶函数#定义-3","388":"/zerdocs/FrontEnd/JavaScript/高阶函数#语法-3","389":"/zerdocs/FrontEnd/JavaScript/高阶函数#用法-3","390":"/zerdocs/FrontEnd/JavaScript/高阶函数#自定义高阶函数","391":"/zerdocs/FrontEnd/JavaScript/高阶函数#字符串数组每项长度、并转换为整数数组","392":"/zerdocs/FrontEnd/JavaScript/高阶函数#语法-4","393":"/zerdocs/FrontEnd/JavaScript/高阶函数#用法-4","394":"/zerdocs/FrontEnd/Shell/自动部署脚本#自动部署","395":"/zerdocs/FrontEnd/Shell/自动部署脚本#脚本","396":"/zerdocs/FrontEnd/Shell/自动部署脚本#action","397":"/zerdocs/FrontEnd/TypeScript/初学笔记#基础语法","398":"/zerdocs/FrontEnd/TypeScript/初学笔记#一、基础类型","399":"/zerdocs/FrontEnd/TypeScript/初学笔记#js类型","400":"/zerdocs/FrontEnd/TypeScript/初学笔记#ts新增类型","401":"/zerdocs/FrontEnd/TypeScript/初学笔记#二、类型声名","402":"/zerdocs/FrontEnd/TypeScript/初学笔记#三、as-const-断言","403":"/zerdocs/FrontEnd/TypeScript/初学笔记#面对对象","404":"/zerdocs/FrontEnd/TypeScript/初学笔记#一、类","405":"/zerdocs/FrontEnd/TypeScript/初学笔记#构造函数","406":"/zerdocs/FrontEnd/TypeScript/初学笔记#二、封装","407":"/zerdocs/FrontEnd/TypeScript/初学笔记#三、属性存取器","408":"/zerdocs/FrontEnd/TypeScript/初学笔记#静态属性","409":"/zerdocs/FrontEnd/TypeScript/初学笔记#四、继承","410":"/zerdocs/FrontEnd/TypeScript/初学笔记#重写","411":"/zerdocs/FrontEnd/TypeScript/初学笔记#五、抽象类-abstract-class","412":"/zerdocs/FrontEnd/TypeScript/初学笔记#六、接口","413":"/zerdocs/FrontEnd/TypeScript/初学笔记#基本配置","414":"/zerdocs/FrontEnd/TypeScript/初学笔记#一、ts编译配置","415":"/zerdocs/FrontEnd/TypeScript/初学笔记#二、webpack整合","416":"/zerdocs/FrontEnd/TypeScript/初学笔记#_1-初始化项目","417":"/zerdocs/FrontEnd/TypeScript/初学笔记#_2-下载构建工具","418":"/zerdocs/FrontEnd/TypeScript/初学笔记#_3-配置webpack","419":"/zerdocs/FrontEnd/TypeScript/初学笔记#_4-配置ts编译选项","420":"/zerdocs/FrontEnd/TypeScript/初学笔记#_5-修改package-json配置","421":"/zerdocs/FrontEnd/TypeScript/初学笔记#_6-项目使用","422":"/zerdocs/FrontEnd/TypeScript/初学笔记#_7-babel","423":"/zerdocs/FrontEnd/TypeScript/初学笔记#_7-2-修改webpack-config-js配置文件","424":"/zerdocs/FrontEnd/TypeScript/进阶使用技巧#松散类型自动推推导","425":"/zerdocs/FrontEnd/TypeScript/配置文件详解#typescript-配置文件-tsconfig-json-解析","426":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_1-experimentaldecorators","427":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_2-strictpropertyinitialization","428":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_3-noimplicitany","429":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_4-target","430":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_5-module","431":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_6-lib","432":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_7-moduleresolution","433":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_8-paths","434":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_9-strictnullchecks","435":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_10-nounusedlocals","436":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_11-nounusedparameters","437":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_12-allowjs","438":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_13-typeroots和types","439":"/zerdocs/FrontEnd/TypeScript/配置文件详解#_14-files、include和exclude","440":"/zerdocs/FrontEnd/TypeScript/配置文件详解#tsconfig-json全解析","441":"/zerdocs/GoodTool/#实用工具集锦","442":"/zerdocs/Interview/Brower/事件循环机制#事件循环机制","443":"/zerdocs/Interview/Brower/事件循环机制#进程与线程","444":"/zerdocs/Interview/Brower/事件循环机制#浏览器的线程与进程","445":"/zerdocs/Interview/Brower/事件循环机制#渲染进程任务","446":"/zerdocs/Interview/Brower/事件循环机制#事件循环","447":"/zerdocs/Interview/Brower/事件循环机制#如何理解异步","448":"/zerdocs/Interview/Brower/事件循环机制#消息队列","449":"/zerdocs/Interview/Brower/浏览器网页请求过程#浏览器网页请求过程","450":"/zerdocs/Interview/Brower/浏览器网页请求过程#一、域名解析","451":"/zerdocs/Interview/Brower/浏览器网页请求过程#二、与服务器建立连接","452":"/zerdocs/Interview/Brower/浏览器网页请求过程#三、发起-http-请求","453":"/zerdocs/Interview/Brower/浏览器网页请求过程#请求报文结构","454":"/zerdocs/Interview/Brower/浏览器网页请求过程#四、服务器端响应-http-请求-浏览器得到-html-代码","455":"/zerdocs/Interview/Brower/浏览器网页请求过程#五、浏览器渲染过程","456":"/zerdocs/Interview/Brower/浏览器网页请求过程#一、解析-html","457":"/zerdocs/Interview/Brower/浏览器网页请求过程#二、解析-css","458":"/zerdocs/Interview/Brower/浏览器网页请求过程#三、样式计算","459":"/zerdocs/Interview/Brower/浏览器网页请求过程#四、布局layout","460":"/zerdocs/Interview/Brower/浏览器网页请求过程#五、分层layer","461":"/zerdocs/Interview/Brower/浏览器网页请求过程#六、绘制paint","462":"/zerdocs/Interview/Brower/浏览器网页请求过程#七、分块tiling","463":"/zerdocs/Interview/Brower/浏览器网页请求过程#八、光栅化raster","464":"/zerdocs/Interview/Brower/浏览器网页请求过程#九、画draw","465":"/zerdocs/Interview/Brower/浏览器网页请求过程#回流reflow","466":"/zerdocs/Interview/Brower/浏览器网页请求过程#重绘repaint","467":"/zerdocs/Interview/Brower/浏览器网页请求过程#六、浏览器对页面进行渲染呈现给用户-关闭连接","468":"/zerdocs/Interview/Brower/浏览器网页请求过程#四次挥手","469":"/zerdocs/Interview/Brower/计算机网络#http与https区别","470":"/zerdocs/Interview/Brower/计算机网络#前端缓存","471":"/zerdocs/Interview/Brower/计算机网络#http缓存","472":"/zerdocs/Interview/Brower/计算机网络#浏览器缓存","473":"/zerdocs/Interview/CSS/基础面试题#css基础面试题","474":"/zerdocs/Interview/CSS/基础面试题#水平垂直居中","475":"/zerdocs/Interview/CSS/基础面试题#盒模型的理解","476":"/zerdocs/Interview/CSS/基础面试题#css-选择器","477":"/zerdocs/Interview/CSS/基础面试题#如何实现动画","478":"/zerdocs/Interview/CSS/基础面试题#实现渐变背景","479":"/zerdocs/Interview/CSS/基础面试题#定位position","480":"/zerdocs/Interview/CSS/基础面试题#隐藏元素的方式","481":"/zerdocs/Interview/CSS/基础面试题#用css3实现饼图","482":"/zerdocs/Interview/CSS/基础面试题#margin和padding适用场景","483":"/zerdocs/Interview/CSS/基础面试题#可替换元素","484":"/zerdocs/Interview/CSS/基础面试题#canvas和svg区别","485":"/zerdocs/Interview/CSS/基础面试题#使用base64编码的图片具有以下优点","486":"/zerdocs/Interview/CSS/基础面试题#优化大量图片的加载方法-提高用户体验","487":"/zerdocs/Interview/CSS/基础面试题#优雅降级和渐进增强","488":"/zerdocs/Interview/CSS/基础面试题#新项目css架构设计入手方向","489":"/zerdocs/Interview/CSS/基础面试题#tailwindcss断点对应设备","490":"/zerdocs/Interview/CSS/进阶面试题#实现一个元素的宽高比","491":"/zerdocs/Interview/CSS/进阶面试题#sass-中-mixin-与-extend的区别","492":"/zerdocs/Interview/JavaScript/Promise相关#前端如何做到并发请求","493":"/zerdocs/Interview/JavaScript/Promise相关#方法一-封装队列","494":"/zerdocs/Interview/JavaScript/Promise相关#方法二-函数封装","495":"/zerdocs/Interview/JavaScript/Promise相关#web-worker","496":"/zerdocs/Interview/JavaScript/Promise相关#service-worker","497":"/zerdocs/Interview/JavaScript/Promise相关#特性","498":"/zerdocs/Interview/JavaScript/原型与原型链#new-对象的执行过程","499":"/zerdocs/Interview/JavaScript/原型与原型链#原型和原型链","500":"/zerdocs/Interview/JavaScript/原型与原型链#函数的隐式原型对象","501":"/zerdocs/Interview/JavaScript/原型与原型链#js继承有哪些方式","502":"/zerdocs/Interview/JavaScript/原型与原型链#方式一-es6","503":"/zerdocs/Interview/JavaScript/原型与原型链#方式二-原型链继承","504":"/zerdocs/Interview/JavaScript/原型与原型链#方式三-借用构造函数继承","505":"/zerdocs/Interview/JavaScript/基础面试题#常见基础面试题","506":"/zerdocs/Interview/JavaScript/基础面试题#数据类型","507":"/zerdocs/Interview/JavaScript/基础面试题#类型检测方式","508":"/zerdocs/Interview/JavaScript/基础面试题#数据类型转换","509":"/zerdocs/Interview/JavaScript/基础面试题#其他类型转为数字类型","510":"/zerdocs/Interview/JavaScript/基础面试题#其他类型转为字符串","511":"/zerdocs/Interview/JavaScript/基础面试题#其他类型转为布尔类型","512":"/zerdocs/Interview/JavaScript/基础面试题#相等与全等区别","513":"/zerdocs/Interview/JavaScript/基础面试题#怎么解决精度问题","514":"/zerdocs/Interview/JavaScript/基础面试题#var-let-const-区别","515":"/zerdocs/Interview/JavaScript/基础面试题#const","516":"/zerdocs/Interview/JavaScript/基础面试题#暂存性死区","517":"/zerdocs/Interview/JavaScript/基础面试题#this指向","518":"/zerdocs/Interview/JavaScript/基础面试题#防抖与节流","519":"/zerdocs/Interview/JavaScript/基础面试题#防抖","520":"/zerdocs/Interview/JavaScript/基础面试题#节流","521":"/zerdocs/Interview/JavaScript/基础面试题#前端本地存储方式","522":"/zerdocs/Interview/JavaScript/基础面试题#区别","523":"/zerdocs/Interview/JavaScript/基础面试题#用法","524":"/zerdocs/Interview/JavaScript/基础面试题#generator","525":"/zerdocs/Interview/JavaScript/基础面试题#异步流程同步化","526":"/zerdocs/Interview/JavaScript/基础面试题#requestanimationframe","527":"/zerdocs/Interview/JavaScript/基础面试题#浅拷贝和深拷贝","528":"/zerdocs/Interview/JavaScript/基础面试题#事件捕获和冒泡机制","529":"/zerdocs/Interview/JavaScript/基础面试题#promise链式调用","530":"/zerdocs/Interview/JavaScript/字符串常用方法#字符串常用方法","531":"/zerdocs/Interview/JavaScript/字符串常用方法#charcodeat与fromcharcode","532":"/zerdocs/Interview/JavaScript/字符串常用方法#slice-与-substring区别","533":"/zerdocs/Interview/JavaScript/字符串常用方法#valueof-与-tostring-的异同","534":"/zerdocs/Interview/JavaScript/进阶面试题#常见进阶面试题","535":"/zerdocs/Interview/JavaScript/进阶面试题#模块化","536":"/zerdocs/Interview/JavaScript/进阶面试题#闭包","537":"/zerdocs/Interview/JavaScript/进阶面试题#应用","538":"/zerdocs/Interview/JavaScript/进阶面试题#弊端","539":"/zerdocs/Interview/JavaScript/进阶面试题#函数柯里化","540":"/zerdocs/Interview/JavaScript/进阶面试题#compose","541":"/zerdocs/Interview/JavaScript/进阶面试题#闭包惰性思想","542":"/zerdocs/Interview/JavaScript/进阶面试题#深度优先和广度优先","543":"/zerdocs/Interview/JavaScript/进阶面试题#深度优先遍历-dfs","544":"/zerdocs/Interview/JavaScript/进阶面试题#广度优先遍历-bfs","545":"/zerdocs/Interview/JavaScript/进阶面试题#两者的区别","546":"/zerdocs/Interview/JavaScript/进阶面试题#广度优先遍历的应用","547":"/zerdocs/Interview/JavaScript/进阶面试题#深度优先遍历的应用","548":"/zerdocs/Interview/JavaScript/进阶面试题#loader和plugin区别","549":"/zerdocs/Interview/JavaScript/进阶面试题#前端模块化规范","550":"/zerdocs/Interview/JavaScript/高级面试题#常见高级面试题","551":"/zerdocs/Interview/JavaScript/高级面试题#怎么禁止下载图片-midjourney实现","552":"/zerdocs/Interview/Vue/Vue响应式原理#数组劫持原理","553":"/zerdocs/Interview/Vue/Vue基础篇#对mvvm的理解","554":"/zerdocs/Interview/Vue/Vue基础篇#mixins的原理","555":"/zerdocs/Interview/Vue/Vue声明周期#vue声明周期","556":"/zerdocs/Interview/Vue/Vue声明周期#嵌套组件组件执行顺序","557":"/zerdocs/Interview/Vue/Vue声明周期#beforecreate-与-created-区别","558":"/zerdocs/Interview/Vue/Vue声明周期#created-与-mounted-区别","559":"/zerdocs/Interview/Vue/Vue声明周期#keep-alive内置缓存组件","560":"/zerdocs/Interview/Vue/Vue声明周期#虚拟-dom-vnode-和-dom","561":"/zerdocs/Interview/Vue/Vue声明周期#vue3-0性能提升","562":"/zerdocs/Interview/Vue/npm run xxx执行过程#npm-run-xxx执行过程","563":"/zerdocs/Interview/Vue/npm run xxx执行过程#vue-cli-项目","564":"/zerdocs/Interview/Vue/npm run xxx执行过程#vite项目","565":"/zerdocs/Interview/Vue/前端项目优化#前端项目优化","566":"/zerdocs/Interview/Vue/前端项目优化#html","567":"/zerdocs/Interview/Vue/前端项目优化#css","568":"/zerdocs/Interview/Vue/前端项目优化#javascript","569":"/zerdocs/Interview/Vue/前端项目优化#构建优化","570":"/zerdocs/Interview/Vue/前端项目优化#移除console","571":"/zerdocs/Interview/Vue/前端项目优化#分包和共享依赖","572":"/zerdocs/Interview/Vue/常见Path区别#vuerouter的-base","573":"/zerdocs/Interview/Vue/常见Path区别#vue-config-js的-publicpath","574":"/zerdocs/Interview/Vue/自定义指令#一键复制","575":"/zerdocs/Interview/#面试","576":"/zerdocs/Problem/Graphical/Antv代码片段集锦#网络拓扑图代码","577":"/zerdocs/Problem/Graphical/Antv代码片段集锦#图实例化","578":"/zerdocs/Problem/Graphical/Antv代码片段集锦#注册节点","579":"/zerdocs/Problem/Graphical/Antv使用总结#一、默认收缩二级节点","580":"/zerdocs/Problem/Graphical/Antv使用总结#二、改用iconfont文字不居中问题","581":"/zerdocs/Problem/Graphical/Antv使用总结#三、初始化画图完成后出现这个锯齿","582":"/zerdocs/Problem/Graphical/Echarts问题总结#echarts问题总结","583":"/zerdocs/Problem/Graphical/Echarts问题总结#屏幕适配问题","584":"/zerdocs/Problem/Graphical/Echarts问题总结#左侧菜单折叠响应式","585":"/zerdocs/Problem/Graphical/Echarts问题总结#地图缩放重叠问题","586":"/zerdocs/Problem/Nuxt3/Nuxt3项目踩坑#uncaught-typeerror-cannot-read-properties-of-undefined-reading-prototype","587":"/zerdocs/Problem/Nuxt3/Nuxt3项目踩坑#hidden-与自定义变体不能一起用","588":"/zerdocs/Problem/Nuxt3/Nuxt3项目踩坑#项目一直报-element-相关错误","589":"/zerdocs/Problem/Nuxt3/Nuxt3项目踩坑#跨域问题","590":"/zerdocs/Problem/Nuxt3/Nuxt3项目踩坑#nuxt-simple-sitemap插件使用问题","591":"/zerdocs/Problem/VitePress/VitePress踩坑记录#vitepress踩坑记录","592":"/zerdocs/Problem/VitePress/VitePress踩坑记录#err-invalid-file-url-host","593":"/zerdocs/Problem/VitePress/VitePress踩坑记录#形成原因-全局替换时粗心大意造成img-src属性多了个","594":"/zerdocs/Problem/VitePress/VitePress踩坑记录#解决","595":"/zerdocs/Problem/VitePress/VitePress踩坑记录#实现自动生成文章左侧侧边栏","596":"/zerdocs/Problem/VitePress/VitePress踩坑记录#痛点及需求","597":"/zerdocs/Problem/VitePress/VitePress踩坑记录#想法及实现","598":"/zerdocs/Problem/VitePress/VitePress踩坑记录#在package-json添加脚本执行命令","599":"/zerdocs/Problem/VitePress/VitePress踩坑记录#在博客根目录新建scripts目录并创建文件getsidebar-ts-添加如下代码","600":"/zerdocs/Problem/VitePress/VitePress踩坑记录#vitepress添加本地搜索功能","601":"/zerdocs/Problem/VitePress/VitePress踩坑记录#安装插件","602":"/zerdocs/Problem/VitePress/VitePress踩坑记录#添加和配置插件","603":"/zerdocs/Problem/VitePress/VitePress踩坑记录#样式覆盖","604":"/zerdocs/Problem/VitePress/VuePress踩坑记录#vuepress踩坑记录","605":"/zerdocs/Problem/VitePress/VuePress踩坑记录#坑点一、自定义目录不能根据视口固定","606":"/zerdocs/Problem/VitePress/VuePress踩坑记录#坑点二、引用的gitee图床图片没显示","607":"/zerdocs/Problem/VitePress/VuePress踩坑记录#坑点三、hexo博客源码没有备份-误点vscode放弃所有更改并且回退版本","608":"/zerdocs/Problem/VueProject/Vue项目踩坑一#vue项目踩坑一","609":"/zerdocs/Problem/VueProject/Vue项目踩坑一#点击弹窗父子传值成功-但是数据没有展示","610":"/zerdocs/Problem/VueProject/Vue项目踩坑一#确定-按钮点击失效问题","611":"/zerdocs/Problem/VueProject/Vue项目踩坑一#文本溢出隐藏处理后对不齐问题","612":"/zerdocs/Problem/VueProject/Vue项目踩坑一#路由组件切换-事件总线意外多次触发","613":"/zerdocs/Problem/VueProject/Vue项目踩坑一#前端配合-nginx-服务开启-gzip-页面加载不出来","614":"/zerdocs/Problem/VueProject/Vue项目踩坑一#tailwindcss动态绑定类不能随着渐变","615":"/zerdocs/Problem/VueProject/Vue项目踩坑一#监听非-window-resize-事件不生效问题","616":"/zerdocs/Problem/#编程踩坑积累与总结"},"fieldIds":{"title":0,"titles":1,"text":2},"fieldLength":{"0":[2,1,10],"1":[2,1,21],"2":[2,1,21],"3":[2,1,1],"4":[2,3,88],"5":[2,3,39],"6":[2,3,23],"7":[2,3,40],"8":[2,1,1],"9":[2,2,28],"10":[2,2,31],"11":[2,2,32],"12":[2,2,68],"13":[2,2,76],"14":[1,1,15],"15":[2,1,152],"16":[2,1,46],"17":[2,3,17],"18":[2,1,26],"19":[2,1,5],"20":[4,3,53],"21":[2,3,46],"22":[2,3,59],"23":[3,1,5],"24":[3,4,6],"25":[2,4,27],"26":[2,1,14],"27":[3,1,9],"28":[3,4,21],"29":[3,4,69],"30":[2,1,52],"31":[3,3,1],"32":[3,3,1],"33":[3,1,1],"34":[4,4,36],"35":[2,4,31],"36":[2,4,64],"37":[2,4,38],"38":[2,4,36],"39":[2,1,1],"40":[3,3,9],"41":[3,3,12],"42":[3,3,95],"43":[3,3,157],"44":[2,1,1],"45":[2,2,49],"46":[2,2,109],"47":[2,1,11],"48":[2,1,8],"49":[2,1,11],"50":[2,1,1],"51":[2,1,37],"52":[2,1,2],"53":[2,1,1],"54":[2,3,9],"55":[2,3,73],"56":[2,3,53],"57":[1,5,9],"58":[1,5,9],"59":[1,5,27],"60":[1,5,1],"61":[2,1,96],"62":[2,1,35],"63":[1,5,15],"64":[1,5,23],"65":[2,1,3],"66":[2,4,21],"67":[2,4,1],"68":[2,4,1],"69":[2,1,1],"70":[2,3,9],"71":[2,3,1],"72":[2,3,27],"73":[1,1,15],"74":[1,1,1],"75":[1,1,20],"76":[1,1,1],"77":[2,1,5],"78":[2,4,17],"79":[2,4,10],"80":[2,4,17],"81":[2,4,2],"82":[2,4,24],"83":[2,1,1],"84":[2,4,48],"85":[2,4,20],"86":[2,4,25],"87":[2,4,13],"88":[2,4,11],"89":[2,4,37],"90":[2,4,33],"91":[2,4,34],"92":[2,4,47],"93":[2,4,33],"94":[2,4,9],"95":[2,4,40],"96":[3,4,57],"97":[2,1,1],"98":[1,4,20],"99":[1,4,19],"100":[1,4,6],"101":[1,4,15],"102":[1,1,24],"103":[1,1,53],"104":[1,1,53],"105":[1,1,58],"106":[1,1,60],"107":[1,1,43],"108":[1,1,101],"109":[1,1,85],"110":[1,1,1],"111":[1,1,25],"112":[1,1,42],"113":[1,1,155],"114":[1,1,67],"115":[1,1,1],"116":[2,2,71],"117":[2,2,30],"118":[2,2,39],"119":[1,1,29],"120":[1,1,1],"121":[2,2,90],"122":[2,2,99],"123":[3,2,59],"124":[1,1,15],"125":[3,2,61],"126":[3,2,85],"127":[1,1,1],"128":[2,2,19],"129":[2,2,28],"130":[1,2,55],"131":[1,1,1],"132":[2,2,35],"133":[2,2,11],"134":[2,2,22],"135":[2,2,16],"136":[2,1,1],"137":[1,3,80],"138":[2,1,1],"139":[1,3,58],"140":[1,3,45],"141":[1,3,23],"142":[1,3,1],"143":[1,4,43],"144":[1,4,79],"145":[1,4,54],"146":[1,3,62],"147":[1,3,118],"148":[1,1,1],"149":[2,1,28],"150":[1,1,25],"151":[2,2,27],"152":[2,2,27],"153":[2,2,30],"154":[1,1,1],"155":[1,1,1],"156":[1,1,24],"157":[1,1,104],"158":[3,1,96],"159":[2,1,57],"160":[1,1,1],"161":[1,1,13],"162":[1,1,1],"163":[1,1,1],"164":[2,2,5],"165":[1,2,22],"166":[1,2,12],"167":[1,2,14],"168":[1,2,47],"169":[1,2,1],"170":[1,2,36],"171":[1,1,1],"172":[1,2,26],"173":[1,2,17],"174":[1,2,25],"175":[1,1,1],"176":[1,1,19],"177":[1,1,39],"178":[1,1,39],"179":[1,1,37],"180":[2,1,13],"181":[4,1,17],"182":[1,4,1],"183":[1,5,12],"184":[1,5,17],"185":[1,5,17],"186":[1,5,30],"187":[1,4,1],"188":[1,5,13],"189":[1,5,38],"190":[1,5,40],"191":[1,4,20],"192":[1,5,8],"193":[1,5,11],"194":[1,5,12],"195":[1,5,75],"196":[1,4,1],"197":[1,5,35],"198":[1,5,31],"199":[1,5,20],"200":[1,5,10],"201":[4,5,11],"202":[1,5,12],"203":[1,5,20],"204":[1,1,1],"205":[1,1,30],"206":[1,1,16],"207":[1,1,19],"208":[1,1,12],"209":[2,1,13],"210":[1,1,36],"211":[1,1,56],"212":[1,1,11],"213":[2,1,39],"214":[1,1,17],"215":[1,1,1],"216":[1,2,9],"217":[1,2,19],"218":[2,1,25],"219":[5,4,1],"220":[5,3,30],"221":[3,3,32],"222":[1,1,23],"223":[1,1,4],"224":[1,1,19],"225":[1,1,15],"226":[1,1,3],"227":[2,2,24],"228":[2,2,8],"229":[1,1,15],"230":[2,1,47],"231":[1,1,49],"232":[2,1,18],"233":[2,1,14],"234":[3,1,86],"235":[3,1,50],"236":[1,1,1],"237":[1,1,3],"238":[2,2,21],"239":[2,2,35],"240":[3,2,33],"241":[1,4,11],"242":[1,4,22],"243":[1,4,51],"244":[3,1,1],"245":[1,3,25],"246":[2,3,18],"247":[2,3,28],"248":[2,1,1],"249":[2,2,30],"250":[2,2,27],"251":[2,1,20],"252":[2,1,11],"253":[2,1,8],"254":[2,1,10],"255":[2,1,44],"256":[2,1,25],"257":[2,1,24],"258":[2,1,11],"259":[2,1,15],"260":[2,1,27],"261":[2,1,16],"262":[1,1,73],"263":[2,1,31],"264":[2,1,27],"265":[1,1,61],"266":[1,1,20],"267":[1,1,15],"268":[1,1,48],"269":[1,1,44],"270":[1,2,57],"271":[1,2,42],"272":[1,2,19],"273":[1,1,1],"274":[1,2,49],"275":[1,2,25],"276":[1,2,20],"277":[3,2,18],"278":[2,1,34],"279":[1,1,70],"280":[1,1,1],"281":[1,2,17],"282":[1,2,53],"283":[1,2,33],"284":[1,2,10],"285":[1,2,39],"286":[1,1,1],"287":[1,2,30],"288":[1,2,52],"289":[1,2,34],"290":[1,2,40],"291":[1,2,31],"292":[1,1,47],"293":[1,1,33],"294":[1,1,34],"295":[1,1,56],"296":[1,1,61],"297":[1,1,34],"298":[1,1,42],"299":[1,1,45],"300":[1,1,34],"301":[1,1,68],"302":[1,1,140],"303":[2,1,54],"304":[2,1,40],"305":[2,1,18],"306":[2,1,18],"307":[2,1,38],"308":[2,1,50],"309":[2,1,28],"310":[2,1,36],"311":[2,1,46],"312":[2,1,16],"313":[4,1,37],"314":[4,1,40],"315":[2,1,84],"316":[1,1,67],"317":[1,1,1],"318":[1,2,112],"319":[1,2,81],"320":[3,1,1],"321":[1,3,11],"322":[4,4,41],"323":[4,4,15],"324":[5,4,39],"325":[1,3,25],"326":[4,4,50],"327":[4,4,24],"328":[5,4,18],"329":[2,1,18],"330":[1,1,27],"331":[1,1,23],"332":[1,1,17],"333":[1,1,36],"334":[1,1,39],"335":[1,1,49],"336":[1,1,10],"337":[2,1,1],"338":[1,1,5],"339":[2,1,3],"340":[3,1,15],"341":[4,1,31],"342":[3,1,22],"343":[2,1,1],"344":[2,1,6],"345":[3,1,48],"346":[3,1,74],"347":[3,1,58],"348":[1,3,27],"349":[2,1,42],"350":[2,1,49],"351":[1,3,1],"352":[1,3,1],"353":[1,3,1],"354":[1,1,1],"355":[1,2,1],"356":[1,2,1],"357":[3,1,70],"358":[1,1,1],"359":[1,2,17],"360":[1,2,14],"361":[1,2,1],"362":[2,3,22],"363":[1,3,21],"364":[1,3,40],"365":[1,3,39],"366":[1,1,1],"367":[1,2,8],"368":[1,2,19],"369":[1,2,1],"370":[1,3,32],"371":[1,3,19],"372":[1,3,18],"373":[2,3,18],"374":[1,3,28],"375":[1,3,23],"376":[2,1,1],"377":[1,3,3],"378":[1,3,41],"379":[1,3,1],"380":[1,4,17],"381":[1,4,17],"382":[1,4,16],"383":[1,4,23],"384":[1,4,25],"385":[1,4,34],"386":[2,1,1],"387":[1,3,10],"388":[1,3,38],"389":[1,3,28],"390":[1,1,1],"391":[2,3,1],"392":[1,2,18],"393":[1,2,36],"394":[1,1,1],"395":[1,1,34],"396":[1,1,128],"397":[1,1,1],"398":[2,2,1],"399":[1,4,70],"400":[1,4,76],"401":[2,2,13],"402":[4,2,35],"403":[1,1,1],"404":[2,2,24],"405":[1,4,23],"406":[2,2,52],"407":[2,2,32],"408":[1,4,25],"409":[2,2,27],"410":[1,4,32],"411":[5,2,22],"412":[2,2,22],"413":[1,1,1],"414":[2,2,117],"415":[2,2,2],"416":[2,4,8],"417":[2,4,14],"418":[2,4,109],"419":[2,4,9],"420":[3,4,20],"421":[2,4,7],"422":[2,4,26],"423":[5,4,30],"424":[1,1,27],"425":[5,1,19],"426":[2,5,44],"427":[2,5,35],"428":[2,5,27],"429":[2,5,33],"430":[2,5,25],"431":[2,5,29],"432":[2,5,56],"433":[2,5,35],"434":[2,5,55],"435":[2,5,13],"436":[2,5,9],"437":[2,5,7],"438":[2,5,16],"439":[3,5,22],"440":[2,5,186],"441":[1,1,1],"442":[1,1,1],"443":[1,1,20],"444":[1,1,20],"445":[1,1,16],"446":[1,1,22],"447":[1,1,32],"448":[1,1,41],"449":[1,1,26],"450":[2,1,61],"451":[2,1,16],"452":[4,1,11],"453":[1,5,6],"454":[7,1,8],"455":[2,1,29],"456":[3,3,55],"457":[3,3,12],"458":[2,3,18],"459":[2,3,9],"460":[2,3,2],"461":[2,3,2],"462":[2,3,2],"463":[2,3,9],"464":[2,3,14],"465":[1,3,35],"466":[1,3,36],"467":[3,1,1],"468":[1,4,21],"469":[1,1,10],"470":[1,1,1],"471":[1,2,27],"472":[1,2,4],"473":[1,1,1],"474":[1,1,39],"475":[1,1,29],"476":[2,1,21],"477":[1,1,11],"478":[1,1,44],"479":[1,1,41],"480":[1,1,1],"481":[1,1,24],"482":[1,1,55],"483":[1,1,19],"484":[1,1,42],"485":[2,1,30],"486":[3,1,35],"487":[1,1,10],"488":[1,1,26],"489":[1,1,31],"490":[1,1,30],"491":[5,1,36],"492":[1,1,25],"493":[2,2,70],"494":[2,2,75],"495":[2,1,46],"496":[2,1,14],"497":[1,1,27],"498":[2,1,40],"499":[1,1,24],"500":[1,2,15],"501":[1,1,1],"502":[2,2,21],"503":[2,2,19],"504":[2,2,19],"505":[1,1,1],"506":[1,1,32],"507":[1,2,35],"508":[1,1,1],"509":[1,2,60],"510":[1,2,20],"511":[1,2,9],"512":[1,1,71],"513":[1,1,14],"514":[4,1,19],"515":[1,5,13],"516":[1,5,16],"517":[1,1,11],"518":[1,1,9],"519":[1,2,58],"520":[1,2,54],"521":[1,1,1],"522":[1,3,23],"523":[1,2,40],"524":[1,1,28],"525":[1,2,45],"526":[1,1,25],"527":[1,1,61],"528":[1,1,30],"529":[1,1,13],"530":[1,1,38],"531":[1,2,16],"532":[3,2,31],"533":[4,2,44],"534":[1,1,1],"535":[1,1,21],"536":[1,1,53],"537":[1,2,3],"538":[1,2,4],"539":[1,1,52],"540":[1,2,40],"541":[1,2,23],"542":[1,1,14],"543":[3,2,48],"544":[3,2,51],"545":[1,2,6],"546":[1,2,8],"547":[1,2,18],"548":[1,1,38],"549":[1,1,26],"550":[1,1,1],"551":[3,1,112],"552":[1,1,16],"553":[1,1,18],"554":[1,1,43],"555":[1,1,13],"556":[1,2,9],"557":[4,1,1],"558":[4,1,5],"559":[2,1,16],"560":[4,1,35],"561":[2,1,7],"562":[3,1,1],"563":[3,3,33],"564":[1,3,24],"565":[1,1,1],"566":[1,1,1],"567":[1,1,1],"568":[1,1,1],"569":[1,1,1],"570":[1,2,26],"571":[1,2,44],"572":[2,1,47],"573":[4,1,79],"574":[1,1,61],"575":[1,1,3],"576":[1,1,1],"577":[1,1,182],"578":[1,1,294],"579":[2,1,11],"580":[2,1,23],"581":[2,1,1],"582":[1,1,1],"583":[1,1,21],"584":[1,1,64],"585":[1,1,68],"586":[10,1,55],"587":[2,10,23],"588":[3,1,24],"589":[1,1,42],"590":[3,1,35],"591":[1,1,1],"592":[5,1,20],"593":[4,6,1],"594":[1,6,14],"595":[1,1,1],"596":[1,2,10],"597":[1,2,1],"598":[2,3,1],"599":[3,3,117],"600":[1,1,5],"601":[1,2,11],"602":[1,2,46],"603":[1,2,46],"604":[1,1,1],"605":[2,1,30],"606":[2,1,5],"607":[3,1,15],"608":[1,1,1],"609":[2,1,38],"610":[3,1,138],"611":[1,1,21],"612":[2,1,18],"613":[5,1,26],"614":[1,1,46],"615":[4,1,58],"616":[1,1,5]},"averageFieldLength":[1.6758508914100478,2.072933549432737,28.74068071312804],"storedFields":{"0":{"title":"一、相关概念","titles":[null]},"1":{"title":"二、数据库操作","titles":[null]},"2":{"title":"三、集合相关操作","titles":[null]},"3":{"title":"四、文档相关操作","titles":[null]},"4":{"title":"1.查询","titles":[null,"四、文档相关操作"]},"5":{"title":"2.插入","titles":[null,"四、文档相关操作"]},"6":{"title":"3.删除","titles":[null,"四、文档相关操作"]},"7":{"title":"4.更新","titles":[null,"四、文档相关操作"]},"8":{"title":"五、","titles":[null]},"9":{"title":"1.插入","titles":[null,"五、"]},"10":{"title":"2.删除","titles":[null,"五、"]},"11":{"title":"3.更新","titles":[null,"五、"]},"12":{"title":"4.查询","titles":[null,"五、"]},"13":{"title":"5.模型","titles":[null,"五、"]},"14":{"title":"Node大文件上传","titles":[]},"15":{"title":"Vue 前端代码","titles":["Node大文件上传"]},"16":{"title":"一、读取文件","titles":[null]},"17":{"title":"path 路径模块","titles":[null,"一、读取文件"]},"18":{"title":"二、写入文件","titles":[null]},"19":{"title":"三、服务器操作","titles":[null]},"20":{"title":"1.创建 web 服务器步骤","titles":[null,"三、服务器操作"]},"21":{"title":"2.动态响应内容","titles":[null,"三、服务器操作"]},"22":{"title":"3.响应文件内容","titles":[null,"三、服务器操作"]},"23":{"title":"四、Node 模块化","titles":[null]},"24":{"title":"1.module 对象","titles":[null,"四、Node 模块化"]},"25":{"title":"2.模块共享","titles":[null,"四、Node 模块化"]},"26":{"title":"五、模块加载机制","titles":[null]},"27":{"title":"六、Express 模块","titles":[null]},"28":{"title":"1.Express 创建服务器","titles":[null,"六、Express 模块"]},"29":{"title":"2.Express 中间件","titles":[null,"六、Express 模块"]},"30":{"title":"七、编写接口","titles":[null]},"31":{"title":"1. CORS 跨域资源共享","titles":[null,"七、编写接口"]},"32":{"title":"2.CORS 头部","titles":[null,"七、编写接口"]},"33":{"title":"八、Node 连接数据库","titles":[null]},"34":{"title":"1.配置 mysql 模块","titles":[null,"八、Node 连接数据库"]},"35":{"title":"2.查询数据","titles":[null,"八、Node 连接数据库"]},"36":{"title":"3.插入数据","titles":[null,"八、Node 连接数据库"]},"37":{"title":"4.更新数据","titles":[null,"八、Node 连接数据库"]},"38":{"title":"5.删除数据","titles":[null,"八、Node 连接数据库"]},"39":{"title":"九、身份认证","titles":[null]},"40":{"title":"1. http 协议的特性","titles":[null,"九、身份认证"]},"41":{"title":"2.Cookie 特性","titles":[null,"九、身份认证"]},"42":{"title":"3.Session 认证","titles":[null,"九、身份认证"]},"43":{"title":"4.JWT 认证","titles":[null,"九、身份认证"]},"44":{"title":"Node 简单上传文件","titles":[]},"45":{"title":"Vue 前端代码","titles":["Node 简单上传文件"]},"46":{"title":"Express 后端代码","titles":["Node 简单上传文件"]},"47":{"title":"一、解决痛点","titles":[null]},"48":{"title":"二、优点和应用","titles":[null]},"49":{"title":"三、基本组成","titles":[null]},"50":{"title":"四、工作原理","titles":[null]},"51":{"title":"五、CentOS安装Docker","titles":[null]},"52":{"title":"六、阿里云镜像加速","titles":[null]},"53":{"title":"七、常用命令","titles":[null]},"54":{"title":"1. Docker","titles":[null,"七、常用命令"]},"55":{"title":"2. 镜像","titles":[null,"七、常用命令"]},"56":{"title":"3. 容器","titles":[null,"七、常用命令"]},"57":{"title":"启动守护式","titles":[null,"七、常用命令","3. 容器"]},"58":{"title":"查看容器日志","titles":[null,"七、常用命令","3. 容器"]},"59":{"title":"容器备份到主机","titles":[null,"七、常用命令","3. 容器"]},"60":{"title":"容器卷","titles":[null,"七、常用命令","3. 容器"]},"61":{"title":"八、","titles":[null]},"62":{"title":"九、Docker网络","titles":[null]},"63":{"title":"共用网卡","titles":[null,"九、Docker网络","3. 容器"]},"64":{"title":"自定义网络","titles":[null,"九、Docker网络","3. 容器"]},"65":{"title":"十、","titles":[null]},"66":{"title":"1.","titles":[null,"十、","3. 容器"]},"67":{"title":"2.","titles":[null,"十、","3. 容器"]},"68":{"title":"3.","titles":[null,"十、","3. 容器"]},"69":{"title":"一、Nginx安装","titles":[null]},"70":{"title":"1.安装命令","titles":[null,"一、Nginx安装"]},"71":{"title":"2.Linux目录结构","titles":[null,"一、Nginx安装"]},"72":{"title":"3.基础命令","titles":[null,"一、Nginx安装"]},"73":{"title":"编写配置","titles":[null]},"74":{"title":"日志分析器","titles":[null]},"75":{"title":"CentOS7联网","titles":[null]},"76":{"title":"Angular基础总结一","titles":[]},"77":{"title":"一、NgModule","titles":["Angular基础总结一"]},"78":{"title":"@NgModule元数据","titles":["Angular基础总结一","一、NgModule",null]},"79":{"title":"declarations 数组","titles":["Angular基础总结一","一、NgModule",null]},"80":{"title":"imports 数组","titles":["Angular基础总结一","一、NgModule",null]},"81":{"title":"providers 数组","titles":["Angular基础总结一","一、NgModule",null]},"82":{"title":"bootstrap 数组","titles":["Angular基础总结一","一、NgModule",null]},"83":{"title":"二、模板基础语法","titles":["Angular基础总结一"]},"84":{"title":"1. 模板表达式","titles":["Angular基础总结一","二、模板基础语法",null]},"85":{"title":"2. 模板来源","titles":["Angular基础总结一","二、模板基础语法",null]},"86":{"title":"3. 属性绑定","titles":["Angular基础总结一","二、模板基础语法",null]},"87":{"title":"4. 自定义属性绑定","titles":["Angular基础总结一","二、模板基础语法",null]},"88":{"title":"5. 插值表达式属性绑定","titles":["Angular基础总结一","二、模板基础语法",null]},"89":{"title":"6. 单个class样式绑定","titles":["Angular基础总结一","二、模板基础语法",null]},"90":{"title":"7. 绑定多个class","titles":["Angular基础总结一","二、模板基础语法",null]},"91":{"title":"8. 绑定单个style","titles":["Angular基础总结一","二、模板基础语法",null]},"92":{"title":"9. 绑定多个style","titles":["Angular基础总结一","二、模板基础语法",null]},"93":{"title":"10. 绑定事件","titles":["Angular基础总结一","二、模板基础语法",null]},"94":{"title":"11. 输入与输出属性","titles":["Angular基础总结一","二、模板基础语法",null]},"95":{"title":"输入属性@Input","titles":["Angular基础总结一","二、模板基础语法",null]},"96":{"title":"输出属性@Output()","titles":["Angular基础总结一","二、模板基础语法",null]},"97":{"title":"三、组件样式","titles":["Angular基础总结一"]},"98":{"title":"宿主选择器","titles":["Angular基础总结一","三、组件样式",null]},"99":{"title":"祖先选择器","titles":["Angular基础总结一","三、组件样式",null]},"100":{"title":"样式模块化","titles":["Angular基础总结一","三、组件样式",null]},"101":{"title":"视图封装模式","titles":["Angular基础总结一","三、组件样式",null]},"102":{"title":"组件投影","titles":[null]},"103":{"title":"ViewChild","titles":[null]},"104":{"title":"ViewChildren","titles":[null]},"105":{"title":"ContentChild","titles":[null]},"106":{"title":"ContentChildren","titles":[null]},"107":{"title":"自定义管道","titles":[null]},"108":{"title":"非纯管道","titles":[null]},"109":{"title":"生命周期","titles":[null]},"110":{"title":"变更检测","titles":[null]},"111":{"title":"默认策略下触发变更检测的时机","titles":[null]},"112":{"title":"onPush下触发变更检测时机","titles":[null]},"113":{"title":"动态组件","titles":[null]},"114":{"title":"NgTemplateOutlet指令","titles":[null]},"115":{"title":"双向绑定","titles":[null]},"116":{"title":"1. 基本双向绑定","titles":[null,"双向绑定"]},"117":{"title":"2. input双向绑定","titles":[null,"双向绑定"]},"118":{"title":"3. 表单Form中双向绑定","titles":[null,"双向绑定"]},"119":{"title":"属性型指令","titles":[null]},"120":{"title":"结构型指令","titles":[null]},"121":{"title":"*ngIf指令","titles":[null,"结构型指令"]},"122":{"title":"*ngFor指令","titles":[null,"结构型指令"]},"123":{"title":"[ngSwitch]指令","titles":[null,"结构型指令"]},"124":{"title":"自定义指令","titles":[null]},"125":{"title":"自定义高亮指令(属性型)","titles":[null,"自定义指令"]},"126":{"title":"自定义unless指令(结构型)","titles":[null,"自定义指令"]},"127":{"title":"模板元素","titles":[null]},"128":{"title":"ng-template","titles":[null,"模板元素"]},"129":{"title":"ng-container","titles":[null,"模板元素"]},"130":{"title":"模板引用变量","titles":[null,"模板元素"]},"131":{"title":"操作符","titles":[null]},"132":{"title":"管道 |","titles":[null,"操作符"]},"133":{"title":"安全链?","titles":[null,"操作符"]},"134":{"title":"非空断言!","titles":[null,"操作符"]},"135":{"title":"类型转换函数$any()","titles":[null,"操作符"]},"136":{"title":"一、前置知识","titles":[null]},"137":{"title":"虚拟DOM","titles":[null,"一、前置知识"]},"138":{"title":"二、组件","titles":[null]},"139":{"title":"函数式组件","titles":[null,"二、组件"]},"140":{"title":"类式组件","titles":[null,"二、组件"]},"141":{"title":"补充","titles":[null,"二、组件"]},"142":{"title":"组实例三大属性","titles":[null,"二、组件"]},"143":{"title":"state","titles":[null,"二、组件","组实例三大属性"]},"144":{"title":"props","titles":[null,"二、组件","组实例三大属性"]},"145":{"title":"refs","titles":[null,"二、组件","组实例三大属性"]},"146":{"title":"事件处理","titles":[null,"二、组件"]},"147":{"title":"组件生命周期","titles":[null,"二、组件"]},"148":{"title":"Vite底层原理学习","titles":[]},"149":{"title":"构建工具承担:","titles":["Vite底层原理学习"]},"150":{"title":"inheritAttrs","titles":[null]},"151":{"title":"场景一:","titles":[null,"inheritAttrs"]},"152":{"title":"场景二:","titles":[null,"inheritAttrs"]},"153":{"title":"场景三:","titles":[null,"inheritAttrs"]},"154":{"title":"分页与搜索条件记录并回显优化","titles":[]},"155":{"title":"整体逻辑","titles":["分页与搜索条件记录并回显优化"]},"156":{"title":"Store","titles":["分页与搜索条件记录并回显优化"]},"157":{"title":"Mixins","titles":["分页与搜索条件记录并回显优化"]},"158":{"title":"列表页 xxxList.vue","titles":["分页与搜索条件记录并回显优化"]},"159":{"title":"一、删除最后一条数据跳转到上一页","titles":[]},"160":{"title":"Grid布局学习笔记","titles":[]},"161":{"title":"实用网站","titles":["Grid布局学习笔记"]},"162":{"title":"基本概念","titles":["Grid布局学习笔记"]},"163":{"title":"容器属性","titles":["Grid布局学习笔记"]},"164":{"title":"开启 Grid布局","titles":["Grid布局学习笔记","容器属性"]},"165":{"title":"容器划分行列","titles":["Grid布局学习笔记","容器属性"]},"166":{"title":"调整间距属性","titles":["Grid布局学习笔记","容器属性"]},"167":{"title":"容器内网格对齐方式","titles":["Grid布局学习笔记","容器属性"]},"168":{"title":"网格内项目对其方式","titles":["Grid布局学习笔记","容器属性"]},"169":{"title":"项目排列顺序","titles":["Grid布局学习笔记","容器属性"]},"170":{"title":"容器中区域定义","titles":["Grid布局学习笔记","容器属性"]},"171":{"title":"项目属性","titles":["Grid布局学习笔记"]},"172":{"title":"合并单元格属性","titles":["Grid布局学习笔记","项目属性"]},"173":{"title":"项目区域定义","titles":["Grid布局学习笔记","项目属性"]},"174":{"title":"单个项目位置","titles":["Grid布局学习笔记","项目属性"]},"175":{"title":"CSS常用代码段","titles":[]},"176":{"title":"单行与多行溢出隐藏","titles":["CSS常用代码段"]},"177":{"title":"自定义滚动条","titles":["CSS常用代码段"]},"178":{"title":"画布网状满天星背景","titles":["CSS常用代码段"]},"179":{"title":"轮播闪光","titles":["CSS常用代码段"]},"180":{"title":"flex布局子元素给了高度,实际渲染确有小数点问题","titles":["CSS常用代码段"]},"181":{"title":"妙妙怪的《CSS 揭秘》读书摘要","titles":[]},"182":{"title":"背景与边框","titles":["妙妙怪的《CSS 揭秘》读书摘要"]},"183":{"title":"多重边框","titles":["妙妙怪的《CSS 揭秘》读书摘要","背景与边框"]},"184":{"title":"灵活的背景定位","titles":["妙妙怪的《CSS 揭秘》读书摘要","背景与边框"]},"185":{"title":"边框内圆角","titles":["妙妙怪的《CSS 揭秘》读书摘要","背景与边框"]},"186":{"title":"条纹背景","titles":["妙妙怪的《CSS 揭秘》读书摘要","背景与边框"]},"187":{"title":"形状","titles":["妙妙怪的《CSS 揭秘》读书摘要"]},"188":{"title":"圆角","titles":["妙妙怪的《CSS 揭秘》读书摘要","形状"]},"189":{"title":"平行四边形","titles":["妙妙怪的《CSS 揭秘》读书摘要","形状"]},"190":{"title":"梯形","titles":["妙妙怪的《CSS 揭秘》读书摘要","形状"]},"191":{"title":"视觉效果","titles":["妙妙怪的《CSS 揭秘》读书摘要"]},"192":{"title":"双侧投影","titles":["妙妙怪的《CSS 揭秘》读书摘要","视觉效果"]},"193":{"title":"染色效果","titles":["妙妙怪的《CSS 揭秘》读书摘要","视觉效果"]},"194":{"title":"毛玻璃","titles":["妙妙怪的《CSS 揭秘》读书摘要","视觉效果"]},"195":{"title":"折角效果","titles":["妙妙怪的《CSS 揭秘》读书摘要","视觉效果"]},"196":{"title":"字体排印","titles":["妙妙怪的《CSS 揭秘》读书摘要"]},"197":{"title":"插入换行","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"198":{"title":"文本行斑马线","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"199":{"title":"自定义下划线","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"200":{"title":"凹凸印刷文字效果","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"201":{"title":"满幅背景、定宽内容(页脚)","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"202":{"title":"紧贴底部的页脚","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"203":{"title":"闪烁效果","titles":["妙妙怪的《CSS 揭秘》读书摘要","字体排印"]},"204":{"title":"Git常用操作","titles":[]},"205":{"title":"拉取最新提交","titles":["Git常用操作"]},"206":{"title":"删除远程分支","titles":["Git常用操作"]},"207":{"title":"删除Tag","titles":["Git常用操作"]},"208":{"title":"删除远程文件","titles":["Git常用操作"]},"209":{"title":"fork后的仓库,拉取合并原仓库的更新","titles":["Git常用操作"]},"210":{"title":"合并多次提交","titles":["Git常用操作"]},"211":{"title":"关联多个代码托管平台","titles":["Git常用操作"]},"212":{"title":"改错分支但为未提交","titles":["Git常用操作"]},"213":{"title":"提交完未推送前,需要再次提交","titles":["Git常用操作"]},"214":{"title":"修改第一次提交信息","titles":["Git常用操作"]},"215":{"title":"代码提交到了错误的分支","titles":["Git常用操作"]},"216":{"title":"方法一","titles":["Git常用操作","代码提交到了错误的分支"]},"217":{"title":"方法二","titles":["Git常用操作","代码提交到了错误的分支"]},"218":{"title":"Git 提交规范化","titles":["Git常用操作"]},"219":{"title":"注意:需要 git init后才能初始化,否则报错如下","titles":["Git常用操作","Git 提交规范化","方法二"]},"220":{"title":"@commitlint/cli与@commitlint/config-conventional","titles":["Git常用操作","Git 提交规范化"]},"221":{"title":"cz-conventional-changelog","titles":["Git常用操作","Git 提交规范化"]},"222":{"title":"安装","titles":[null]},"223":{"title":"预览所有主题命令","titles":[null]},"224":{"title":"初始化并应用主题","titles":[null]},"225":{"title":"分隔符乱码问题","titles":[null]},"226":{"title":"配置PowerShell","titles":[null]},"227":{"title":"1.打开配置文件方式一","titles":[null,"配置PowerShell"]},"228":{"title":"2.打开配置文件方式二","titles":[null,"配置PowerShell"]},"229":{"title":"自定义主题","titles":[null]},"230":{"title":"VS Code终端配置","titles":[null]},"231":{"title":"隐藏提示语","titles":[null]},"232":{"title":"1.生成公钥和私钥","titles":[null]},"233":{"title":"2.在代码托管平台设置添加公钥","titles":[null]},"234":{"title":"3.添加私钥到ssh-agent中","titles":[null]},"235":{"title":"4.创建config件,打开编辑","titles":[null]},"236":{"title":"SSH公钥私钥加密解密原理","titles":[null]},"237":{"title":"Javascript实现异步","titles":[]},"238":{"title":"方式一:回调函数","titles":["Javascript实现异步",null]},"239":{"title":"方式二:Promise","titles":["Javascript实现异步",null]},"240":{"title":"语法糖:async /await","titles":["Javascript实现异步",null]},"241":{"title":"实现fn1先执行","titles":["Javascript实现异步",null,"语法糖:async /await"]},"242":{"title":"捕获异常","titles":["Javascript实现异步",null,"语法糖:async /await"]},"243":{"title":"使用陷阱","titles":["Javascript实现异步",null,"语法糖:async /await"]},"244":{"title":"if else 多分支优化","titles":[]},"245":{"title":"简单分支","titles":["if else 多分支优化"]},"246":{"title":"条件单一,处理不同","titles":["if else 多分支优化"]},"247":{"title":"条件复杂,处理也复杂","titles":["if else 多分支优化"]},"248":{"title":"JS 图片懒加载","titles":[]},"249":{"title":"方案一:监听滚动","titles":["JS 图片懒加载"]},"250":{"title":"方案二:观察者","titles":["JS 图片懒加载"]},"251":{"title":"1.算术运算符","titles":[null,null]},"252":{"title":"2.赋值运算符","titles":[null,null]},"253":{"title":"3..运算符","titles":[null,null]},"254":{"title":"4.自增和自减","titles":[null,null]},"255":{"title":"5.逻辑运算符","titles":[null,null]},"256":{"title":"6.关系运算符","titles":[null,null]},"257":{"title":"7.相等运算符","titles":[null,null]},"258":{"title":"8.条件运算符","titles":[null,null]},"259":{"title":"9.控制语句","titles":[null,null]},"260":{"title":"10.循环语句","titles":[null,null]},"261":{"title":"11.数据类型","titles":[null,null]},"262":{"title":"this指向","titles":[null,null]},"263":{"title":"可变参数 arguments","titles":[null,null]},"264":{"title":"剩余参数 ...args","titles":[null,null]},"265":{"title":"Map","titles":[null,null]},"266":{"title":"Set","titles":[null,null]},"267":{"title":"随机数生成","titles":[null,null]},"268":{"title":"时间格式化","titles":[null,null]},"269":{"title":"面向对象之类","titles":[null,null]},"270":{"title":"封装","titles":[null,null,"面向对象之类"]},"271":{"title":"继承","titles":[null,null,"面向对象之类"]},"272":{"title":"多态","titles":[null,null,"面向对象之类"]},"273":{"title":"对象的结构","titles":[null,null]},"274":{"title":"原型","titles":[null,null,"对象的结构"]},"275":{"title":"原型链","titles":[null,null,"对象的结构"]},"276":{"title":"修改原型","titles":[null,null,"对象的结构"]},"277":{"title":"instanceof/in/hasOwn","titles":[null,null,"对象的结构"]},"278":{"title":"10.new运算符","titles":[null,null]},"279":{"title":"括号匹配","titles":[null]},"280":{"title":"简单递归","titles":[null]},"281":{"title":"计算阶乘","titles":[null,"简单递归"]},"282":{"title":"扁平化数组","titles":[null,"简单递归"]},"283":{"title":"反转字符串","titles":[null,"简单递归"]},"284":{"title":"求最大公约数","titles":[null,"简单递归"]},"285":{"title":"斐波那契数列","titles":[null,"简单递归"]},"286":{"title":"排序算法","titles":[null]},"287":{"title":"冒泡排序","titles":[null,"排序算法"]},"288":{"title":"选择排序","titles":[null,"排序算法"]},"289":{"title":"快速排序","titles":[null,"排序算法"]},"290":{"title":"插入排序","titles":[null,"排序算法"]},"291":{"title":"希尔排序","titles":[null,"排序算法"]},"292":{"title":"求两个有序数组的中位数","titles":[null]},"293":{"title":"实现EventEmitter","titles":[null]},"294":{"title":"返回给定起止字符串月份中间所有月份","titles":[null]},"295":{"title":"实现Promise的all方法","titles":[null]},"296":{"title":"LRU缓存算法","titles":[null]},"297":{"title":"不使用乘法符号乘法函数","titles":[null]},"298":{"title":"链表反转","titles":[null]},"299":{"title":"二叉树的遍历","titles":[null]},"300":{"title":"二叉搜索树的插入和查找","titles":[null]},"301":{"title":"字符串搜索算法","titles":[null]},"302":{"title":"数字转中文","titles":[null]},"303":{"title":"一、声名Promise并绑定this","titles":[null]},"304":{"title":"二、状态保护与执行者异步捕获","titles":[null]},"305":{"title":"三、then方法构建","titles":[null]},"306":{"title":"四、实现then异步","titles":[null]},"307":{"title":"五、解决同步代码需要等待执行问题","titles":[null]},"308":{"title":"六、then的链式操作","titles":[null]},"309":{"title":"七、返回值的判断与处理","titles":[null]},"310":{"title":"八、代码优化及复用","titles":[null]},"311":{"title":"九、返回类型约束","titles":[null]},"312":{"title":"十、实现resolve和reject","titles":[null]},"313":{"title":"十一、Promise.all()实现","titles":[null]},"314":{"title":"十二、实现Promise.race()","titles":[null]},"315":{"title":"十三、完整代码","titles":[null]},"316":{"title":"基本数据类型","titles":[null]},"317":{"title":"对象数组去重","titles":[null]},"318":{"title":"对象相同比较","titles":[null,"对象数组去重"]},"319":{"title":"对象数组去重","titles":[null,"对象数组去重"]},"320":{"title":"JS常用的求交集、并集、差集的方法","titles":[]},"321":{"title":"普通数组","titles":["JS常用的求交集、并集、差集的方法"]},"322":{"title":"一、并集(A∪B)","titles":["JS常用的求交集、并集、差集的方法","普通数组"]},"323":{"title":"二、交集(A∩B)","titles":["JS常用的求交集、并集、差集的方法","普通数组"]},"324":{"title":"三、差集(A-B)","titles":["JS常用的求交集、并集、差集的方法","普通数组"]},"325":{"title":"对象数组","titles":["JS常用的求交集、并集、差集的方法"]},"326":{"title":"一、并集(A∪B)","titles":["JS常用的求交集、并集、差集的方法","对象数组"]},"327":{"title":"二、交集(A∩B)","titles":["JS常用的求交集、并集、差集的方法","对象数组"]},"328":{"title":"三、差集(A-B)","titles":["JS常用的求交集、并集、差集的方法","对象数组"]},"329":{"title":"Blob与 File","titles":[null]},"330":{"title":"ArrayBuffer","titles":[null]},"331":{"title":"FileReader","titles":[null]},"332":{"title":"DataView","titles":[null]},"333":{"title":"FilePicker","titles":[null]},"334":{"title":"文件操作","titles":[null]},"335":{"title":"URL","titles":[null]},"336":{"title":"参考资料","titles":[null]},"337":{"title":"资料参考:","titles":[null]},"338":{"title":"应用场景","titles":[null]},"339":{"title":"可视化工具:","titles":[null]},"340":{"title":"1. 或者 |","titles":[null]},"341":{"title":"2. 原子表[]、原子组()","titles":[null]},"342":{"title":"3. 边界符^、$","titles":[null]},"343":{"title":"4. 元字符","titles":[null]},"344":{"title":"5. 匹配所有字符","titles":[null]},"345":{"title":"6. 模式修正符号i、g","titles":[null]},"346":{"title":"7. 原子组中的原子表([-\\\\/])","titles":[null]},"347":{"title":"8.贪婪匹配+、*、?","titles":[null]},"348":{"title":"批量验证密码","titles":[null,"8.贪婪匹配+、*、?"]},"349":{"title":"9. matchAll","titles":[null]},"350":{"title":"10. 断言匹配``","titles":[null]},"351":{"title":"将链接替换为想要的网址","titles":[null,"10. 断言匹配``"]},"352":{"title":"将不含oss的替换","titles":[null,"10. 断言匹配``"]},"353":{"title":"模糊电话后四位","titles":[null,"10. 断言匹配``"]},"354":{"title":"案例练习","titles":[null]},"355":{"title":"替换练习","titles":[null,"案例练习"]},"356":{"title":"给原子组起别名","titles":[null,"案例练习"]},"357":{"title":"获取目录结构(纯前端)","titles":[]},"358":{"title":"高阶函数之filter","titles":[null]},"359":{"title":"定义","titles":[null,"高阶函数之filter"]},"360":{"title":"语法","titles":[null,"高阶函数之filter"]},"361":{"title":"用法","titles":[null,"高阶函数之filter"]},"362":{"title":"过滤小于 100","titles":[null,"高阶函数之filter","用法",null]},"363":{"title":"返回奇数元素","titles":[null,"高阶函数之filter","用法",null]},"364":{"title":"数组去重","titles":[null,"高阶函数之filter","用法",null]},"365":{"title":"找出素数","titles":[null,"高阶函数之filter","用法",null]},"366":{"title":"高阶函数之map","titles":[null]},"367":{"title":"定义","titles":[null,"高阶函数之map"]},"368":{"title":"语法","titles":[null,"高阶函数之map"]},"369":{"title":"用法","titles":[null,"高阶函数之map"]},"370":{"title":"返回数组元素平方后的新数组","titles":[null,"高阶函数之map","用法",null]},"371":{"title":"用给定函数创建新字符串","titles":[null,"高阶函数之map","用法",null]},"372":{"title":"把二维数组变字符串","titles":[null,"高阶函数之map","用法",null]},"373":{"title":"数字序列转为数组,删除符号","titles":[null,"高阶函数之map","用法",null]},"374":{"title":"拿到所有图片的图片名称并以数组形式返回","titles":[null,"高阶函数之map","用法",null]},"375":{"title":"vue中循环注册组件","titles":[null,"高阶函数之map","用法",null]},"376":{"title":"高阶函数之 reduce","titles":[null]},"377":{"title":"定义","titles":[null,"高阶函数之 reduce"]},"378":{"title":"语法","titles":[null,"高阶函数之 reduce"]},"379":{"title":"用法","titles":[null,"高阶函数之 reduce"]},"380":{"title":"数组求和","titles":[null,"高阶函数之 reduce","用法",null]},"381":{"title":"数组去重","titles":[null,"高阶函数之 reduce","用法",null]},"382":{"title":"计算两个或多个数字的平均值","titles":[null,"高阶函数之 reduce","用法",null]},"383":{"title":"将多维数组转化为一维","titles":[null,"高阶函数之 reduce","用法",null]},"384":{"title":"对象里的属性求和","titles":[null,"高阶函数之 reduce","用法",null]},"385":{"title":"统计数组中每个元素出现的次数","titles":[null,"高阶函数之 reduce","用法",null]},"386":{"title":"高阶函数之 sort","titles":[null]},"387":{"title":"定义","titles":[null,"高阶函数之 sort"]},"388":{"title":"语法","titles":[null,"高阶函数之 sort"]},"389":{"title":"用法","titles":[null,"高阶函数之 sort"]},"390":{"title":"自定义高阶函数","titles":[null]},"391":{"title":"字符串数组每项长度、并转换为整数数组","titles":[null,"自定义高阶函数","用法"]},"392":{"title":"语法","titles":[null,"自定义高阶函数"]},"393":{"title":"用法","titles":[null,"自定义高阶函数"]},"394":{"title":"自动部署","titles":[]},"395":{"title":"脚本","titles":["自动部署"]},"396":{"title":"Action","titles":["自动部署"]},"397":{"title":"基础语法","titles":[null]},"398":{"title":"一、基础类型","titles":[null,"基础语法"]},"399":{"title":"JS类型","titles":[null,"基础语法","一、基础类型"]},"400":{"title":"TS新增类型","titles":[null,"基础语法","一、基础类型"]},"401":{"title":"二、类型声名","titles":[null,"基础语法"]},"402":{"title":"三、as const 断言","titles":[null,"基础语法"]},"403":{"title":"面对对象","titles":[null]},"404":{"title":"一、类","titles":[null,"面对对象"]},"405":{"title":"构造函数","titles":[null,"面对对象","一、类"]},"406":{"title":"二、封装","titles":[null,"面对对象"]},"407":{"title":"三、属性存取器","titles":[null,"面对对象"]},"408":{"title":"静态属性","titles":[null,"面对对象","三、属性存取器"]},"409":{"title":"四、继承","titles":[null,"面对对象"]},"410":{"title":"重写","titles":[null,"面对对象","四、继承"]},"411":{"title":"五、抽象类(abstract class)","titles":[null,"面对对象"]},"412":{"title":"六、接口","titles":[null,"面对对象"]},"413":{"title":"基本配置","titles":[null]},"414":{"title":"一、TS编译配置","titles":[null,"基本配置"]},"415":{"title":"二、webpack整合","titles":[null,"基本配置"]},"416":{"title":"1. 初始化项目","titles":[null,"基本配置","二、webpack整合"]},"417":{"title":"2. 下载构建工具","titles":[null,"基本配置","二、webpack整合"]},"418":{"title":"3. 配置webpack","titles":[null,"基本配置","二、webpack整合"]},"419":{"title":"4.配置TS编译选项","titles":[null,"基本配置","二、webpack整合"]},"420":{"title":"5 .修改package.json配置","titles":[null,"基本配置","二、webpack整合"]},"421":{"title":"6.项目使用","titles":[null,"基本配置","二、webpack整合"]},"422":{"title":"7.Babel","titles":[null,"基本配置","二、webpack整合"]},"423":{"title":"7.2 修改webpack.config.js配置文件","titles":[null,"基本配置","二、webpack整合"]},"424":{"title":"松散类型自动推推导","titles":[null]},"425":{"title":"Typescript 配置文件(tsconfig.json)解析","titles":[]},"426":{"title":"1. experimentalDecorators","titles":["Typescript 配置文件(tsconfig.json)解析"]},"427":{"title":"2. strictPropertyInitialization","titles":["Typescript 配置文件(tsconfig.json)解析"]},"428":{"title":"3. noImplicitAny","titles":["Typescript 配置文件(tsconfig.json)解析"]},"429":{"title":"4. target","titles":["Typescript 配置文件(tsconfig.json)解析"]},"430":{"title":"5. module","titles":["Typescript 配置文件(tsconfig.json)解析"]},"431":{"title":"6. lib","titles":["Typescript 配置文件(tsconfig.json)解析"]},"432":{"title":"7. moduleResolution","titles":["Typescript 配置文件(tsconfig.json)解析"]},"433":{"title":"8. paths","titles":["Typescript 配置文件(tsconfig.json)解析"]},"434":{"title":"9. strictNullChecks","titles":["Typescript 配置文件(tsconfig.json)解析"]},"435":{"title":"10. noUnusedLocals","titles":["Typescript 配置文件(tsconfig.json)解析"]},"436":{"title":"11. noUnusedParameters","titles":["Typescript 配置文件(tsconfig.json)解析"]},"437":{"title":"12. allowJs","titles":["Typescript 配置文件(tsconfig.json)解析"]},"438":{"title":"13. typeRoots和types","titles":["Typescript 配置文件(tsconfig.json)解析"]},"439":{"title":"14. files、include和exclude","titles":["Typescript 配置文件(tsconfig.json)解析"]},"440":{"title":"tsconfig.json全解析","titles":["Typescript 配置文件(tsconfig.json)解析"]},"441":{"title":"实用工具集锦","titles":[]},"442":{"title":"事件循环机制","titles":[]},"443":{"title":"进程与线程","titles":["事件循环机制"]},"444":{"title":"浏览器的线程与进程","titles":["事件循环机制"]},"445":{"title":"渲染进程任务","titles":["事件循环机制"]},"446":{"title":"事件循环","titles":["事件循环机制"]},"447":{"title":"如何理解异步","titles":["事件循环机制"]},"448":{"title":"消息队列","titles":["事件循环机制"]},"449":{"title":"浏览器网页请求过程","titles":[]},"450":{"title":"一、域名解析","titles":["浏览器网页请求过程"]},"451":{"title":"二、与服务器建立连接","titles":["浏览器网页请求过程"]},"452":{"title":"三、发起 HTTP 请求","titles":["浏览器网页请求过程"]},"453":{"title":"请求报文结构","titles":["浏览器网页请求过程","三、发起 HTTP 请求"]},"454":{"title":"四、服务器端响应 HTTP 请求,浏览器得到 HTML 代码","titles":["浏览器网页请求过程"]},"455":{"title":"五、浏览器渲染过程","titles":["浏览器网页请求过程"]},"456":{"title":"一、解析 HTML","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"457":{"title":"二、解析 CSS","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"458":{"title":"三、样式计算","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"459":{"title":"四、布局Layout","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"460":{"title":"五、分层Layer","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"461":{"title":"六、绘制Paint","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"462":{"title":"七、分块Tiling","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"463":{"title":"八、光栅化Raster","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"464":{"title":"九、画Draw","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"465":{"title":"回流reflow","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"466":{"title":"重绘repaint","titles":["浏览器网页请求过程","五、浏览器渲染过程"]},"467":{"title":"六、浏览器对页面进行渲染呈现给用户,关闭连接","titles":["浏览器网页请求过程"]},"468":{"title":"四次挥手","titles":["浏览器网页请求过程","六、浏览器对页面进行渲染呈现给用户,关闭连接"]},"469":{"title":"http与https区别","titles":[null]},"470":{"title":"前端缓存","titles":[null]},"471":{"title":"HTTP缓存","titles":[null,"前端缓存"]},"472":{"title":"浏览器缓存","titles":[null,"前端缓存"]},"473":{"title":"CSS基础面试题","titles":[]},"474":{"title":"水平垂直居中","titles":["CSS基础面试题"]},"475":{"title":"盒模型的理解","titles":["CSS基础面试题"]},"476":{"title":"CSS 选择器","titles":["CSS基础面试题"]},"477":{"title":"如何实现动画","titles":["CSS基础面试题"]},"478":{"title":"实现渐变背景","titles":["CSS基础面试题"]},"479":{"title":"定位position","titles":["CSS基础面试题"]},"480":{"title":"隐藏元素的方式","titles":["CSS基础面试题"]},"481":{"title":"用css3实现饼图","titles":["CSS基础面试题"]},"482":{"title":"margin和padding适用场景","titles":["CSS基础面试题"]},"483":{"title":"可替换元素","titles":["CSS基础面试题"]},"484":{"title":"Canvas和SVG区别","titles":["CSS基础面试题"]},"485":{"title":"使用Base64编码的图片具有以下优点:","titles":["CSS基础面试题"]},"486":{"title":"优化大量图片的加载方法,提高用户体验:","titles":["CSS基础面试题"]},"487":{"title":"优雅降级和渐进增强","titles":["CSS基础面试题"]},"488":{"title":"新项目css架构设计入手方向","titles":["CSS基础面试题"]},"489":{"title":"Tailwindcss断点对应设备","titles":["CSS基础面试题"]},"490":{"title":"实现一个元素的宽高比","titles":[null]},"491":{"title":"Sass 中@mixin 与@extend的区别","titles":[null]},"492":{"title":"前端如何做到并发请求","titles":[null]},"493":{"title":"方法一:封装队列","titles":[null,"前端如何做到并发请求"]},"494":{"title":"方法二:函数封装","titles":[null,"前端如何做到并发请求"]},"495":{"title":"Web Worker","titles":[null]},"496":{"title":"Service Worker","titles":[null]},"497":{"title":"特性","titles":[null]},"498":{"title":"new 对象的执行过程","titles":[null]},"499":{"title":"原型和原型链","titles":[null]},"500":{"title":"函数的隐式原型对象","titles":[null,"原型和原型链"]},"501":{"title":"JS继承有哪些方式","titles":[null]},"502":{"title":"方式一:ES6","titles":[null,"JS继承有哪些方式"]},"503":{"title":"方式二:原型链继承","titles":[null,"JS继承有哪些方式"]},"504":{"title":"方式三:借用构造函数继承","titles":[null,"JS继承有哪些方式"]},"505":{"title":"常见基础面试题","titles":[]},"506":{"title":"数据类型","titles":["常见基础面试题"]},"507":{"title":"类型检测方式","titles":["常见基础面试题","数据类型"]},"508":{"title":"数据类型转换","titles":["常见基础面试题"]},"509":{"title":"其他类型转为数字类型","titles":["常见基础面试题","数据类型转换"]},"510":{"title":"其他类型转为字符串","titles":["常见基础面试题","数据类型转换"]},"511":{"title":"其他类型转为布尔类型","titles":["常见基础面试题","数据类型转换"]},"512":{"title":"相等与全等区别","titles":["常见基础面试题"]},"513":{"title":"怎么解决精度问题","titles":["常见基础面试题"]},"514":{"title":"var/let/const 区别","titles":["常见基础面试题"]},"515":{"title":"const","titles":["常见基础面试题","var/let/const 区别"]},"516":{"title":"暂存性死区","titles":["常见基础面试题","var/let/const 区别"]},"517":{"title":"this指向","titles":["常见基础面试题"]},"518":{"title":"防抖与节流","titles":["常见基础面试题"]},"519":{"title":"防抖","titles":["常见基础面试题","防抖与节流"]},"520":{"title":"节流","titles":["常见基础面试题","防抖与节流"]},"521":{"title":"前端本地存储方式","titles":["常见基础面试题"]},"522":{"title":"区别","titles":["常见基础面试题","前端本地存储方式","节流"]},"523":{"title":"用法","titles":["常见基础面试题","前端本地存储方式"]},"524":{"title":"Generator","titles":["常见基础面试题"]},"525":{"title":"异步流程同步化","titles":["常见基础面试题","Generator"]},"526":{"title":"requestAnimationFrame","titles":["常见基础面试题"]},"527":{"title":"浅拷贝和深拷贝","titles":["常见基础面试题"]},"528":{"title":"事件捕获和冒泡机制","titles":["常见基础面试题"]},"529":{"title":"Promise链式调用","titles":["常见基础面试题"]},"530":{"title":"字符串常用方法","titles":[null]},"531":{"title":"charCodeAt与fromCharCode","titles":[null,"字符串常用方法"]},"532":{"title":"slice 与 substring区别","titles":[null,"字符串常用方法"]},"533":{"title":"valueOf 与 toString 的异同","titles":[null,"字符串常用方法"]},"534":{"title":"常见进阶面试题","titles":[]},"535":{"title":"模块化","titles":["常见进阶面试题"]},"536":{"title":"闭包","titles":["常见进阶面试题"]},"537":{"title":"应用","titles":["常见进阶面试题","闭包"]},"538":{"title":"弊端","titles":["常见进阶面试题","闭包"]},"539":{"title":"函数柯里化","titles":["常见进阶面试题"]},"540":{"title":"compose","titles":["常见进阶面试题","函数柯里化"]},"541":{"title":"闭包惰性思想","titles":["常见进阶面试题","函数柯里化"]},"542":{"title":"深度优先和广度优先","titles":["常见进阶面试题"]},"543":{"title":"深度优先遍历(DFS)","titles":["常见进阶面试题","深度优先和广度优先"]},"544":{"title":"广度优先遍历(BFS)","titles":["常见进阶面试题","深度优先和广度优先"]},"545":{"title":"两者的区别","titles":["常见进阶面试题","深度优先和广度优先"]},"546":{"title":"广度优先遍历的应用","titles":["常见进阶面试题","深度优先和广度优先"]},"547":{"title":"深度优先遍历的应用","titles":["常见进阶面试题","深度优先和广度优先"]},"548":{"title":"loader和plugin区别","titles":["常见进阶面试题"]},"549":{"title":"前端模块化规范","titles":["常见进阶面试题"]},"550":{"title":"常见高级面试题","titles":[]},"551":{"title":"怎么禁止下载图片(midjourney实现)","titles":["常见高级面试题"]},"552":{"title":"数组劫持原理","titles":[null]},"553":{"title":"对MVVM的理解","titles":[null]},"554":{"title":"Mixins的原理","titles":[null]},"555":{"title":"Vue声明周期","titles":[null]},"556":{"title":"嵌套组件组件执行顺序","titles":[null,"Vue声明周期"]},"557":{"title":"beforeCreate 与 created 区别","titles":[null]},"558":{"title":"created 与 mounted 区别","titles":[null]},"559":{"title":"keep-alive内置缓存组件","titles":[null]},"560":{"title":"虚拟 DOM(VNode) 和 DOM","titles":[null]},"561":{"title":"Vue3.0性能提升","titles":[null]},"562":{"title":"npm run xxx执行过程","titles":[]},"563":{"title":"vue cli 项目","titles":["npm run xxx执行过程"]},"564":{"title":"vite项目","titles":["npm run xxx执行过程"]},"565":{"title":"前端项目优化","titles":[]},"566":{"title":"HTML","titles":["前端项目优化"]},"567":{"title":"CSS","titles":["前端项目优化"]},"568":{"title":"JavaScript","titles":["前端项目优化"]},"569":{"title":"构建优化","titles":["前端项目优化"]},"570":{"title":"移除console","titles":["前端项目优化","构建优化"]},"571":{"title":"分包和共享依赖","titles":["前端项目优化","构建优化"]},"572":{"title":"VueRouter的 base","titles":[null]},"573":{"title":"vue.config.js的 publicPath","titles":[null]},"574":{"title":"一键复制","titles":[null]},"575":{"title":"面试","titles":[]},"576":{"title":"网络拓扑图代码","titles":[]},"577":{"title":"图实例化","titles":["网络拓扑图代码"]},"578":{"title":"注册节点","titles":["网络拓扑图代码"]},"579":{"title":"一、默认收缩二级节点","titles":[null,null]},"580":{"title":"二、改用iconfont文字不居中问题","titles":[null,null]},"581":{"title":"三、初始化画图完成后出现这个锯齿","titles":[null,null]},"582":{"title":"Echarts问题总结","titles":[]},"583":{"title":"屏幕适配问题","titles":["Echarts问题总结"]},"584":{"title":"左侧菜单折叠响应式","titles":["Echarts问题总结"]},"585":{"title":"地图缩放重叠问题","titles":["Echarts问题总结"]},"586":{"title":"Uncaught TypeError: Cannot read properties of undefined (reading \'prototype\')","titles":[null]},"587":{"title":"hidden 与自定义变体不能一起用","titles":[null,"Uncaught TypeError: Cannot read properties of undefined (reading \'prototype\')"]},"588":{"title":"项目一直报 Element 相关错误","titles":[null]},"589":{"title":"跨域问题","titles":[null]},"590":{"title":"nuxt-simple-sitemap插件使用问题","titles":[null]},"591":{"title":"VitePress踩坑记录","titles":[]},"592":{"title":"ERR_INVALID_FILE_URL_HOST","titles":["VitePress踩坑记录"]},"593":{"title":"形成原因:全局替换时粗心大意造成img src属性多了个\'/\'","titles":["VitePress踩坑记录","ERR_INVALID_FILE_URL_HOST"]},"594":{"title":"解决","titles":["VitePress踩坑记录","ERR_INVALID_FILE_URL_HOST"]},"595":{"title":"实现自动生成文章左侧侧边栏","titles":["VitePress踩坑记录"]},"596":{"title":"痛点及需求","titles":["VitePress踩坑记录","实现自动生成文章左侧侧边栏"]},"597":{"title":"想法及实现","titles":["VitePress踩坑记录","实现自动生成文章左侧侧边栏"]},"598":{"title":"在package.json添加脚本执行命令","titles":["VitePress踩坑记录","实现自动生成文章左侧侧边栏","想法及实现"]},"599":{"title":"在博客根目录新建scripts目录并创建文件getSidebar.ts,添加如下代码","titles":["VitePress踩坑记录","实现自动生成文章左侧侧边栏","想法及实现"]},"600":{"title":"VitePress添加本地搜索功能","titles":["VitePress踩坑记录"]},"601":{"title":"安装插件","titles":["VitePress踩坑记录","VitePress添加本地搜索功能"]},"602":{"title":"添加和配置插件","titles":["VitePress踩坑记录","VitePress添加本地搜索功能"]},"603":{"title":"样式覆盖","titles":["VitePress踩坑记录","VitePress添加本地搜索功能"]},"604":{"title":"VuePress踩坑记录","titles":[]},"605":{"title":"坑点一、自定义目录不能根据视口固定","titles":["VuePress踩坑记录"]},"606":{"title":"坑点二、引用的Gitee图床图片没显示","titles":["VuePress踩坑记录"]},"607":{"title":"坑点三、Hexo博客源码没有备份,误点VsCode放弃所有更改并且回退版本","titles":["VuePress踩坑记录"]},"608":{"title":"Vue项目踩坑一","titles":[]},"609":{"title":"点击弹窗父子传值成功,但是数据没有展示","titles":["Vue项目踩坑一"]},"610":{"title":"\'确定\'按钮点击失效问题","titles":["Vue项目踩坑一"]},"611":{"title":"文本溢出隐藏处理后对不齐问题","titles":["Vue项目踩坑一"]},"612":{"title":"路由组件切换,事件总线意外多次触发","titles":["Vue项目踩坑一"]},"613":{"title":"前端配合 Nginx 服务开启 gzip 页面加载不出来","titles":["Vue项目踩坑一"]},"614":{"title":"TailwindCSS动态绑定类不能随着渐变","titles":["Vue项目踩坑一"]},"615":{"title":"监听非 window resize 事件不生效问题","titles":["Vue项目踩坑一"]},"616":{"title":"编程踩坑积累与总结","titles":[]}},"dirtCount":0,"index":[["您需要自己编写代码来检测大小变化",{"2":{"615":1}}],["您的分支和",{"2":{"213":2}}],["背景色的变化",{"2":{"614":2}}],["背景与边框",{"0":{"182":1},"1":{"183":1,"184":1,"185":1,"186":1}}],["恰巧性能优化",{"2":{"609":1}}],["点击弹窗父子传值成功",{"0":{"609":1}}],["点了一下直接回到解放前",{"2":{"607":1}}],["领悟",{"2":{"607":1}}],["搞了好久没办法解决",{"2":{"607":1}}],["天坑",{"2":{"607":1}}],["误点vscode放弃所有更改并且回退版本",{"0":{"607":1}}],["防盗链的问题",{"2":{"606":1}}],["防抖拓展写法",{"2":{"519":1}}],["防抖",{"0":{"519":1},"2":{"518":1}}],["防抖与节流",{"0":{"518":1},"1":{"519":1,"520":1}}],["产生原因",{"2":{"605":1}}],["挠破头皮都没想明白啥原因",{"2":{"605":1}}],["巨坑",{"2":{"605":1,"609":1}}],["情输入关键词",{"2":{"602":2}}],["情输入序号",{"2":{"158":2}}],["放在",{"2":{"602":1}}],["放大",{"2":{"577":2}}],["依据经验放在根目录下不管用",{"2":{"602":1}}],["依次执行以上两步操作",{"2":{"543":1}}],["依次执行以下操作",{"2":{"543":1}}],["依次为树中的每个节点计算出它最终的样式",{"2":{"458":1}}],["想法及实现",{"0":{"597":1},"1":{"598":1,"599":1}}],["想要打开是干干净净的界面",{"2":{"231":1}}],["逐个移除文章文件夹最终才定位到出问题的文档",{"2":{"594":1}}],["又不知道那个文件有问题",{"2":{"594":1}}],["刚开始以为后端改动数据层级嵌套太深vue丢失了响应式的原因",{"2":{"609":1}}],["刚开始以为没有我常用的jetbrain",{"2":{"225":1}}],["刚开始我只能猜到某个文件路径有问题",{"2":{"594":1}}],["业务请求",{"2":{"589":2}}],["果然排除法找到是",{"2":{"588":1}}],["断点后不写自定义的",{"2":{"586":1}}],["断言",{"0":{"402":1}}],["断言匹配``",{"0":{"350":1},"1":{"351":1,"352":1,"353":1}}],["南海诸岛",{"2":{"585":2}}],["延伸会有抖动问题",{"2":{"584":2}}],["延迟加载",{"2":{"486":1}}],["折腾了三遍algolia都没能添加上搜索功能",{"2":{"600":1}}],["折叠时",{"2":{"584":1}}],["折角效果",{"0":{"195":1},"2":{"195":1}}],["侧边栏按钮点击展开",{"2":{"584":1}}],["屏幕适配问题",{"0":{"583":1}}],["弹窗特有节点注册",{"2":{"578":2}}],["箭头动画",{"2":{"578":2}}],["箭头函数指向声明时所在外部作用域",{"2":{"517":1}}],["箭头函数设置函数结构",{"2":{"399":2}}],["箭头函数中没有arguments",{"2":{"262":1}}],["箭头函数没有自身的this",{"2":{"262":1}}],["箭头函数没有自己的this",{"2":{"262":1}}],["箭头函数传参",{"2":{"146":2}}],["线条动画",{"2":{"578":2}}],["线程中",{"2":{"495":1}}],["线程",{"2":{"495":2}}],["线程操纵者一般为程序员",{"2":{"443":1}}],["线程快",{"2":{"443":1}}],["线程可以共享同一个进程间的资源",{"2":{"443":1}}],["线程可以看做轻量级的进程",{"2":{"443":1}}],["线程不能包含进程",{"2":{"443":1}}],["线程是操作系统调度的基本单位",{"2":{"443":1}}],["居中",{"2":{"577":2}}],["缩小",{"2":{"577":2}}],["缩放",{"2":{"464":1}}],["假设你的应用被部署在http",{"2":{"572":1}}],["假设无法确定item的类型",{"2":{"135":1}}],["你就需要手动指定base属性的值",{"2":{"572":1}}],["软链接",{"2":{"564":1}}],["软删除成功",{"2":{"38":2}}],["软删除",{"2":{"38":1}}],["版本",{"2":{"563":1}}],["版本不一样",{"2":{"47":1}}],["环境变量",{"2":{"563":1,"564":1}}],["环境不一致",{"2":{"47":1}}],["源码体积减小",{"2":{"561":1}}],["源仓库地址",{"2":{"396":2}}],["移动端",{"2":{"560":1}}],["移除console",{"0":{"570":1}}],["移除所有",{"2":{"523":1}}],["移除所有localstorage",{"2":{"523":1}}],["移除单个",{"2":{"523":2}}],["移除和插入dom节点",{"2":{"121":1}}],["跨域问题",{"0":{"589":1}}],["跨域资源共享",{"0":{"31":1}}],["跨平台",{"2":{"560":1}}],["性能优化",{"2":{"560":1}}],["性别",{"2":{"144":4}}],["精简许多",{"2":{"560":1}}],["孙子组件",{"2":{"556":2}}],["孙悟空",{"2":{"265":2,"406":6,"407":2}}],["嵌套组件组件执行顺序",{"0":{"556":1}}],["策略中没有定义的策略",{"2":{"554":1}}],["充当数据模型与视图界面的桥梁",{"2":{"553":1}}],["怎么禁止下载图片",{"0":{"551":1}}],["怎么解决精度问题",{"0":{"513":1}}],["采用静态加载模块的方式",{"2":{"549":1}}],["采用同步加载模块的方式",{"2":{"549":1}}],["功能的函数",{"2":{"548":1}}],["广度优先遍历可以用于许多问题",{"2":{"546":1}}],["广度优先遍历的应用",{"0":{"546":1}}],["广度优先遍历的空间复杂度比深度优先遍历高",{"2":{"545":1}}],["广度优先遍历需要使用队列逐层扫描节点",{"2":{"545":1}}],["广度优先遍历",{"0":{"544":1},"2":{"544":1,"547":1}}],["节点文本溢出省略处理",{"2":{"578":2}}],["节点2",{"2":{"542":4}}],["节点1",{"2":{"542":6}}],["节流阀",{"2":{"520":2}}],["节流",{"0":{"520":1},"1":{"522":1},"2":{"518":1}}],["深度优先遍历的应用",{"0":{"547":1}}],["深度优先遍历",{"0":{"543":1},"2":{"543":1}}],["深度优先和广度优先",{"0":{"542":1},"1":{"543":1,"544":1,"545":1,"546":1,"547":1}}],["深拷贝",{"2":{"319":2,"527":1}}],["考虑不传函数",{"2":{"540":2}}],["供其夏季上下文后期使用",{"2":{"540":1}}],["供实例使用",{"2":{"140":2}}],["思想",{"2":{"540":1,"552":1}}],["柯里化",{"2":{"539":2}}],["弊端",{"0":{"538":1}}],["闭包惰性思想",{"0":{"541":1}}],["闭包案例",{"2":{"536":1}}],["闭包",{"0":{"536":1},"1":{"537":1,"538":1},"2":{"536":1}}],["混用",{"2":{"535":1}}],["现在到1970年1月1日的毫秒数",{"2":{"533":1}}],["现在短视频时代",{"2":{"181":1}}],["码对应的字符",{"2":{"531":2}}],["码",{"2":{"531":2}}],["码点",{"2":{"387":1}}],["删",{"2":{"530":1}}],["删除多余的",{"2":{"594":1}}],["删除这个属性",{"2":{"585":2}}],["删除所有",{"2":{"523":1}}],["删除所有sessionstorage",{"2":{"523":1}}],["删除所有文档",{"2":{"6":2}}],["删除编译后的所有的注释",{"2":{"440":2}}],["删除符号",{"0":{"373":1}}],["删除最久未被使用的元素",{"2":{"296":2}}],["删除最后一条数据跳转到上一页",{"0":{"159":1}}],["删除元素",{"2":{"266":2}}],["删除全部的键值对",{"2":{"265":2}}],["删除指定数据",{"2":{"265":2}}],["删除本地所有",{"2":{"207":2}}],["删除本地库tag",{"2":{"207":2}}],["删除本地库分支",{"2":{"206":2}}],["删除tag",{"0":{"207":1}}],["删除远程文件",{"0":{"208":1}}],["删除远程库tag",{"2":{"207":2}}],["删除远程库分支",{"2":{"206":1}}],["删除远程库分支git",{"2":{"206":1}}],["删除远程分支",{"0":{"206":1}}],["删除远程",{"2":{"205":1}}],["删除失败`",{"2":{"159":2}}],["删除成功`",{"2":{"159":2}}],["删除网络",{"2":{"62":2}}],["删除已停止容器",{"2":{"56":2}}],["删除数据",{"0":{"38":1}}],["删除数据库",{"2":{"1":1}}],["删除满足条件的数据db",{"2":{"6":1}}],["删除满足条件的数据",{"2":{"6":3}}],["删除某一条",{"2":{"6":4}}],["删除",{"0":{"6":1,"10":1},"2":{"55":1,"296":4,"523":2}}],["删除集合",{"2":{"2":1}}],["删除集合show",{"2":{"2":1}}],["删除当前所在库",{"2":{"1":1}}],["删除当前所在库use",{"2":{"1":1}}],["阻止同一节点其他后绑定事件执行",{"2":{"528":1}}],["阻止默认行为",{"2":{"528":1}}],["阻止冒泡",{"2":{"528":1}}],["途中会触发绑定事件冒泡元素的回调",{"2":{"528":1}}],["途中会触发绑定事件捕获元素的回调",{"2":{"528":1}}],["浅拷贝",{"2":{"527":2}}],["浅拷贝和深拷贝",{"0":{"527":1}}],["右侧的结果",{"2":{"525":2}}],["跳转的页面可以共享",{"2":{"522":1}}],["跳过第一个索引",{"2":{"378":2}}],["跳过40条数据查30条数据",{"2":{"4":2}}],["存储时间",{"2":{"522":1}}],["存储大小",{"2":{"522":1}}],["存在",{"2":{"514":2}}],["地图缩放重叠问题",{"0":{"585":1}}],["地铁发车时间",{"2":{"520":1}}],["地址",{"2":{"450":1}}],["滚动到底部加载更多",{"2":{"520":1}}],["滚动到元素top小于设定值",{"2":{"479":1}}],["王者荣耀技能冷却",{"2":{"520":1}}],["王者荣耀回城操作",{"2":{"520":1}}],["王五",{"2":{"122":2}}],["设定到期时间自动清除",{"2":{"523":1}}],["设定到期时间自动清除let",{"2":{"523":1}}],["设定时间",{"2":{"520":2}}],["设置这个属性",{"2":{"585":2}}],["设置的时间间隔没办法保证",{"2":{"526":1}}],["设置到期时间",{"2":{"522":1}}],["设置对象的原型",{"2":{"498":1}}],["设置为true",{"2":{"435":1,"436":1}}],["设置为",{"2":{"429":1,"573":1}}],["设置预定义的环境",{"2":{"418":2}}],["设置babel",{"2":{"418":2}}],["设置属性的方法叫做getter方法",{"2":{"407":1}}],["设置属性的方法",{"2":{"407":1}}],["设置高度",{"2":{"91":4}}],["设置文件名称",{"2":{"46":2}}],["设置文件存储位置",{"2":{"46":2}}],["设置浏览器运行最大并发数",{"2":{"15":2}}],["已经解决方案",{"2":{"616":1}}],["已经在处理",{"2":{"520":2}}],["已经有值",{"2":{"519":2}}],["已经检测完的组件",{"2":{"111":1}}],["频繁触发某个事件时",{"2":{"518":2}}],["立即执行函数必定指向window",{"2":{"517":1}}],["区别",{"0":{"514":1,"522":1,"557":1,"558":1},"1":{"515":1,"516":1}}],["区域的对齐方式",{"2":{"168":1}}],["题2",{"2":{"512":2}}],["题1",{"2":{"512":2}}],["剩下的都是转为数字",{"2":{"512":1}}],["剩余参数写到最后",{"2":{"264":2}}],["剩余参数可以接收任意数量实参",{"2":{"264":2}}],["剩余参数",{"0":{"264":1},"2":{"264":2}}],["宇符串转换为数宇",{"2":{"509":1}}],["局限性",{"2":{"507":1}}],["局部变量",{"2":{"121":2}}],["局部中间件",{"2":{"29":1}}],["唯一标识统一管理",{"2":{"506":1}}],["唯一一个需要用额外的",{"2":{"150":1}}],["借用构造函数继承",{"0":{"504":1}}],["顶级构造器",{"2":{"499":2}}],["向内传播",{"2":{"528":1}}],["向服务器发起请求等先关操作",{"2":{"496":1}}],["向客户端发送消息",{"2":{"496":1}}],["向map中添加键值对",{"2":{"265":2}}],["❌",{"2":{"493":2,"494":2}}],["释放占用空间",{"2":{"493":2}}],["异步流程同步化",{"0":{"525":1}}],["异步编程",{"2":{"492":1}}],["异步与事件循环理解",{"2":{"446":1}}],["维持正方形",{"2":{"490":1}}],["维护俩者状态需要消耗额外资源",{"2":{"147":1}}],["维护好主机和ip的关系",{"2":{"64":2}}],["宽度发生改变时",{"2":{"490":1}}],["宽高比",{"2":{"490":2}}],["宽字节匹配",{"2":{"345":2}}],["电脑显示器",{"2":{"489":1}}],["栅格",{"2":{"488":1}}],["公共变量",{"2":{"488":1}}],["公司gitlab主机地址",{"2":{"235":2}}],["针对自己想个兼容的最低版本进行开发",{"2":{"487":1}}],["渐进增强",{"2":{"487":1}}],["渐变",{"2":{"478":2}}],["影响页面加载速度",{"2":{"485":1}}],["尤其是超过几百kb的图片",{"2":{"485":1}}],["海报",{"2":{"484":1}}],["制作标志",{"2":{"484":1}}],["曲线",{"2":{"484":1}}],["矢量图形在放大或缩小时不会失真",{"2":{"486":1}}],["矢量图形还可以编辑和修改",{"2":{"484":1}}],["矢量图形不会失真或模糊",{"2":{"484":1}}],["矢量图形是由数学方程描述的二维图形",{"2":{"484":1}}],["矢量图形",{"2":{"484":1}}],["图实例化",{"0":{"577":1}}],["图文详解深度优先",{"2":{"547":1}}],["图标跟随鼠标",{"2":{"520":1}}],["图表或图标等",{"2":{"484":1}}],["图片初始化完成后调用",{"2":{"551":2}}],["图片等",{"2":{"548":1}}],["图片大小增大",{"2":{"485":1}}],["图片",{"2":{"449":1}}],["图片懒加载",{"0":{"248":1},"1":{"249":1,"250":1}}],["图片压缩",{"2":{"149":1}}],["另外",{"2":{"484":1}}],["另一方面导致页面无法及时更新",{"2":{"447":1}}],["另一个容器名",{"2":{"63":2}}],["额外增加两个声明周期",{"2":{"559":1}}],["额外包一层并加上",{"2":{"482":2}}],["额外的检查",{"2":{"440":2}}],["兄弟相邻元素",{"2":{"482":1}}],["留白处需要背景色时",{"2":{"482":1}}],["留白处不需要背景色时",{"2":{"482":1}}],["黏性定位sticky",{"2":{"479":1}}],["固定定位fixed",{"2":{"479":1}}],["伪元素选择器",{"2":{"476":1}}],["伪类",{"2":{"476":1}}],["伪数组",{"2":{"263":2}}],["权重",{"2":{"476":1}}],["外边距",{"2":{"475":1}}],["外部样式",{"2":{"456":1}}],["外部主机端口",{"2":{"56":2}}],["盒模型从内到外由",{"2":{"475":1}}],["盒模型的理解",{"0":{"475":1}}],["行内元素",{"2":{"474":1}}],["行内样式均会包含在",{"2":{"456":1}}],["协商缓存主要有四个头字段",{"2":{"471":1}}],["协商缓存",{"2":{"471":1}}],["协议隔离",{"2":{"522":1}}],["协议传输数据",{"2":{"452":1}}],["协议",{"2":{"451":1,"452":1}}],["协议的特性",{"0":{"40":1}}],["具体步骤如下",{"2":{"543":1,"544":1}}],["具体做法是当某些任务发生时",{"2":{"447":1}}],["具有生命周期",{"2":{"497":1}}],["具有安全性的ssl加密传输协议",{"2":{"469":1}}],["明文传输",{"2":{"469":1}}],["超过10kb的文件就压缩",{"2":{"613":2}}],["超过",{"2":{"513":1}}],["超过安全数宇的",{"2":{"509":1}}],["超文本传输协议",{"2":{"469":1}}],["超类",{"2":{"271":1}}],["确定更新",{"2":{"610":2}}],["确定",{"0":{"610":1},"2":{"610":2}}],["确定无误后删除文件",{"2":{"208":1}}],["确定无误后删除文件git",{"2":{"208":1}}],["确保服务端关闭再",{"2":{"468":1}}],["风格",{"2":{"466":1}}],["阶段在合成线程中",{"2":{"466":1}}],["阶段由于",{"2":{"466":1}}],["既不会影响布局也不会影响绘制指令",{"2":{"466":1}}],["激活css伪类",{"2":{"465":1}}],["效率高的本质原因",{"2":{"464":1}}],["效果",{"2":{"211":2}}],["倾斜",{"2":{"464":1}}],["旋转",{"2":{"464":1}}],["变量私有化",{"2":{"537":1}}],["变量声明",{"2":{"516":1}}],["变量指向的内存地址",{"2":{"515":1}}],["变量的值不能修改",{"2":{"514":2,"515":1}}],["变量提升",{"2":{"514":1}}],["变形",{"2":{"464":1}}],["变更检测",{"0":{"110":1}}],["很多预设值会变成绝对值",{"2":{"458":1}}],["很多库都有用到该特性",{"2":{"426":1}}],["称之为",{"2":{"458":1}}],["称其为新对象",{"2":{"278":1}}],["率先下载",{"2":{"456":1}}],["率先改变的",{"2":{"314":1}}],["遇到一个非有效数字字符",{"2":{"509":2}}],["遇到",{"2":{"456":1}}],["光栅化raster",{"0":{"463":1}}],["光栅化",{"2":{"455":1}}],["绘制paint",{"0":{"461":1}}],["绘制",{"2":{"455":1}}],["整个渲染流程分为多个阶段",{"2":{"455":1}}],["整体逻辑",{"0":{"155":1}}],["布局完成后形成布局树",{"2":{"459":1}}],["布局layout",{"0":{"459":1}}],["布局",{"2":{"455":2,"482":1}}],["布局方向",{"2":{"176":2}}],["树形图哪个需要收缩则把属性collapsed设置为true",{"2":{"579":2}}],["树阶段",{"2":{"459":1}}],["树中",{"2":{"456":1}}],["树和",{"2":{"456":1}}],["树的生成必须暂停",{"2":{"456":1}}],["树",{"2":{"455":2,"456":2,"458":2,"465":1}}],["树叶形状",{"2":{"188":2}}],["空间复杂度为",{"2":{"543":1,"544":1}}],["空串",{"2":{"511":1}}],["空宇符串变为0",{"2":{"509":1}}],["空行",{"2":{"453":1,"454":1}}],["空白会被浏览器保留",{"2":{"197":2}}],["试探一下对方是否遵循",{"2":{"451":1}}],["首先就是三次握手建立",{"2":{"451":1}}],["首先判断两个值的类型是否相同",{"2":{"318":1}}],["客户端在发送",{"2":{"468":1}}],["客户端的请求到达服务器",{"2":{"451":1}}],["客户端就读取",{"2":{"450":1}}],["客户端就要进行广播查找",{"2":{"450":1}}],["那就可以成功和目标计算机进行通信",{"2":{"450":1}}],["那就无法跟目标计算机进行通信",{"2":{"450":1}}],["那么你就需要设置如下的base属性",{"2":{"572":1}}],["那么后续的then方法会等待该promise对象的状态发生改变后再执行",{"2":{"529":1}}],["那么后续的then方法会被跳过",{"2":{"529":1}}],["那么就宣告这次解析失败",{"2":{"450":1}}],["那么数组会按照该函数的返回值排序",{"2":{"388":1}}],["那么不用在模版里声明",{"2":{"113":1}}],["个变异方法进行重写",{"2":{"552":1}}],["个",{"2":{"507":1,"555":2}}],["个步骤",{"2":{"450":1}}],["个网格",{"2":{"172":2}}],["经过以上的",{"2":{"450":1}}],["‪c",{"2":{"450":1}}],["系统内核",{"2":{"450":1}}],["系统的",{"2":{"450":1}}],["系统",{"2":{"450":1}}],["因学习配置博客用git",{"2":{"607":1}}],["因此",{"2":{"491":1}}],["因此可能会影响页面加载速度",{"2":{"485":1}}],["因此可以更快地加载页面",{"2":{"485":1}}],["因此会使得图片的大小增加约1",{"2":{"485":1}}],["因此相对较难掌握",{"2":{"484":1}}],["因此又带来了偏差",{"2":{"448":1}}],["因而产生错误",{"2":{"451":1}}],["因为vue",{"2":{"572":1}}],["因为广度优先遍历需要使用队列来存储节点",{"2":{"545":1}}],["因为字符串是不可变的",{"2":{"530":1}}],["因为不会阻塞主线程运行",{"2":{"495":1}}],["因为不是字符串",{"2":{"137":2}}],["因为它们是基于数学公式创建的",{"2":{"484":1}}],["因为它们可以被任意的修改",{"2":{"270":1}}],["因为客户端发送完",{"2":{"468":1}}],["因为有操作系统计时函数偏差",{"2":{"448":1}}],["因为有些选项如果你没配置",{"2":{"425":1}}],["因为这个更符合平时我们的书写习惯以及认知",{"2":{"432":1}}],["因为现代大部分应用项目都会使用webpack",{"2":{"429":1}}],["因为没有赋值默认值",{"2":{"427":2}}],["因为应用的主题只在当前窗口有效果",{"2":{"226":1}}],["因为babel编译后开启了严格模式",{"2":{"139":2}}],["因为虚拟dom是react内部在用",{"2":{"137":1}}],["因为",{"2":{"129":2,"466":1}}],["受限制",{"2":{"522":2}}],["受事件循环的影响",{"2":{"448":1}}],["受控组件",{"2":{"141":1}}],["毫秒",{"2":{"448":2}}],["间隔时间少于",{"2":{"448":1}}],["层",{"2":{"448":1}}],["微队列中的任务优先所有其他任务执行",{"2":{"448":1}}],["微风",{"2":{"143":2}}],["消息队列有优先级",{"2":{"448":1}}],["消息队列",{"0":{"448":1}}],["持续进行",{"2":{"446":1}}],["次",{"2":{"445":1}}],["次提交的",{"2":{"210":2}}],["次提交",{"2":{"210":2}}],["浏览器会自动跟踪窗口的大小变化并触发",{"2":{"615":1}}],["浏览器会合并这些操作",{"2":{"465":1}}],["浏览器窗口关闭时",{"2":{"522":1}}],["浏览器窗口大小发生改变",{"2":{"465":1}}],["浏览器可以同时消费多个数据流",{"2":{"492":1}}],["浏览器可以根据实际情况从不同的队列中取出任务执行",{"2":{"448":1}}],["浏览器缓存",{"0":{"472":1}}],["浏览器根据",{"2":{"471":1}}],["浏览器的渲染引擎会根据标准",{"2":{"475":1}}],["浏览器的默认样式",{"2":{"456":1}}],["浏览器的线程与进程",{"0":{"444":1}}],["浏览器在开始解析前",{"2":{"456":1}}],["浏览器在适当的位置自动插入连字符换行",{"2":{"197":2}}],["浏览器渲染过程",{"0":{"455":1},"1":{"456":1,"457":1,"458":1,"459":1,"460":1,"461":1,"462":1,"463":1,"464":1,"465":1,"466":1}}],["浏览器就会发起一个",{"2":{"450":1}}],["浏览器",{"2":{"450":1,"535":1}}],["浏览器对页面进行渲染呈现给用户",{"0":{"467":1},"1":{"468":1},"2":{"449":1}}],["浏览器解析",{"2":{"449":1}}],["浏览器得到",{"0":{"454":1},"2":{"449":1}}],["浏览器网页请求过程",{"0":{"449":1},"1":{"450":1,"451":1,"452":1,"453":1,"454":1,"455":1,"456":1,"457":1,"458":1,"459":1,"460":1,"461":1,"462":1,"463":1,"464":1,"465":1,"466":1,"467":1,"468":1}}],["浏览器实现计时器时",{"2":{"448":1}}],["浏览器必须准备好一个微队列",{"2":{"448":1}}],["浏览器永不阻塞",{"2":{"447":1}}],["浏览器进程内部会启动多个线程处理不同的任务",{"2":{"444":1}}],["浏览器进程",{"2":{"444":1}}],["浏览器是一个多进程多线程的应用程序",{"2":{"444":1}}],["操纵者不同",{"2":{"443":1}}],["操作",{"2":{"560":1}}],["操作非常耗费性能",{"2":{"560":1}}],["操作浏览器样式表",{"2":{"457":1}}],["操作系统就会查找",{"2":{"450":1}}],["操作系统的计时函数本身就有少量偏差",{"2":{"448":1}}],["操作符",{"0":{"131":1},"1":{"132":1,"133":1,"134":1,"135":1}}],["操作dom备用选择",{"2":{"125":2}}],["操作dom",{"2":{"125":2}}],["操作界面",{"2":{"46":2}}],["描述",{"2":{"443":1}}],["描述语言和国家信息的字符串",{"2":{"268":2}}],["支持相互之间的",{"2":{"535":1}}],["支持commonjs",{"2":{"535":1}}],["支持",{"2":{"514":1}}],["支持消息推送",{"2":{"497":1}}],["支持这个特性需要visual",{"2":{"440":2}}],["支持的目标版本",{"2":{"423":2}}],["禁止拖拽",{"2":{"551":1}}],["禁止右键",{"2":{"551":1}}],["禁止贪婪",{"2":{"347":2}}],["禁用函数参数双向协变检查",{"2":{"440":2}}],["抛出错误",{"2":{"440":6}}],["抛出异常或死循环",{"2":{"400":2}}],["抛出异常的级别",{"2":{"7":2}}],["报相关错误",{"2":{"590":1}}],["报文结构参考",{"2":{"454":1}}],["报告",{"2":{"440":4}}],["报错提示",{"2":{"609":1}}],["报错",{"2":{"234":2,"586":2}}],["允许",{"2":{"514":1}}],["允许从没有设置默认导出的模块中默认导入",{"2":{"440":2}}],["允许编译",{"2":{"440":2}}],["允许跨域资源共享",{"2":{"43":2}}],["详细内容可看此处",{"2":{"438":1}}],["详细的说",{"2":{"147":2}}],["理由同上",{"2":{"436":1}}],["顾名思义",{"2":{"435":1}}],["省的每次在不同层级文件import模块时",{"2":{"433":1}}],["平时都是webpack打包",{"2":{"432":1}}],["平行四边形",{"0":{"189":1}}],["笔者建议开启该选项",{"2":{"434":1}}],["笔者建议大家使用node",{"2":{"432":1}}],["笔者根据项目实战经历来解释一些常用的编译选项",{"2":{"425":1}}],["说直白点",{"2":{"432":1}}],["说明插入位置找到",{"2":{"290":2}}],["决定如何处理模块",{"2":{"432":1}}],["然而2016年1月以前",{"2":{"430":1}}],["然而",{"2":{"429":1}}],["然后才能执行后续代码",{"2":{"549":1}}],["然后再一次性渲染到真实",{"2":{"560":1}}],["然后再执行代码",{"2":{"549":1}}],["然后再",{"2":{"509":2}}],["然后再访问左子树和右子树",{"2":{"299":1}}],["然后在后续对高版本的新特性开发",{"2":{"487":1}}],["然后在后续对低版本进行兼容",{"2":{"487":1}}],["然后调用kmp函数来查找匹配位置",{"2":{"301":2}}],["然后逐个字符地扫描文本串和模式串",{"2":{"301":1}}],["然后访问右子树",{"2":{"299":1}}],["然后访问节点",{"2":{"299":1}}],["然后执行后面同步代码",{"2":{"238":2}}],["然后",{"2":{"217":1}}],["绝对定位absolute",{"2":{"479":1}}],["绝对定位",{"2":{"474":2}}],["绝对能省很多事",{"2":{"427":1}}],["绝对路径不利于维护移植",{"2":{"16":1}}],["建议正式项目开启该选项",{"2":{"436":1}}],["建议正式项目将该选项开启",{"2":{"435":1}}],["建议初次上手typescript",{"2":{"428":1}}],["建议请把这个值设为false",{"2":{"427":1}}],["建议把strictpropertyinitialization设置为false",{"2":{"427":1}}],["建议将密钥命名为",{"2":{"43":2}}],["启用装饰器",{"2":{"440":2}}],["启用严格的",{"2":{"440":2}}],["启用所有严格类型检查选项",{"2":{"440":2}}],["启用",{"2":{"426":1,"434":1}}],["启动服务执行命令",{"2":{"563":1}}],["启动服务器",{"2":{"20":1}}],["启动node环境",{"2":{"396":1}}],["启动两个网桥模式容器",{"2":{"64":2}}],["启动守护式",{"0":{"57":1}}],["启动",{"2":{"51":2,"72":1}}],["及settimeout",{"2":{"492":1}}],["及",{"2":{"426":1}}],["及其内容替换为一个注释",{"2":{"128":2}}],["官方解释",{"2":{"426":1,"432":1}}],["稍不留神就会书写出不符合规则的代码",{"2":{"425":1}}],["松散类型自动推推导",{"0":{"424":1}}],["告诉webpack不使用箭头函数",{"2":{"418":2}}],["打包时报错",{"2":{"590":1}}],["打包后文件的名字",{"2":{"418":2}}],["打击自信心",{"2":{"425":1}}],["打开文件",{"2":{"334":2}}],["打开编辑",{"0":{"235":1}}],["打开终端",{"2":{"234":1}}],["打开配置文件方式二",{"0":{"228":1}}],["打开配置文件方式一",{"0":{"227":1}}],["打开并添加需要power",{"2":{"227":1}}],["清除最后一个定时器",{"2":{"519":2}}],["清除上一次",{"2":{"519":4}}],["清除margin塌陷",{"2":{"482":1}}],["清楚dist目录旧文件",{"2":{"418":2}}],["清空",{"2":{"42":2}}],["步骤如下",{"2":{"415":1}}],["严格模式指向window的变为undefined",{"2":{"517":1}}],["严格的类型检查选项",{"2":{"440":2}}],["严格检查空值",{"2":{"414":2}}],["严格要求",{"2":{"399":2}}],["狗在跑~",{"2":{"411":2}}],["抽象方法没有方法体只能定义在抽象类中",{"2":{"411":1}}],["抽象类是专门用来被其他类所继承的类",{"2":{"411":1}}],["抽象类",{"0":{"411":1}}],["抽取方法",{"2":{"310":2}}],["栗子",{"2":{"404":1}}],["永远不返回结果",{"2":{"400":2}}],["任何会改变元素几何信息",{"2":{"465":1}}],["任意类型",{"2":{"400":2}}],["任务没有优先级",{"2":{"448":1}}],["任务",{"2":{"396":2}}],["联合类型",{"2":{"400":2}}],["联合写法",{"2":{"116":1}}],["枚举值",{"2":{"429":1,"430":1}}],["枚举类型",{"2":{"400":2}}],["枚举的值得到它的名字",{"2":{"399":1}}],["枚举的值得到它的名字enum",{"2":{"399":1}}],["枚举",{"2":{"399":1}}],["✅",{"2":{"396":2,"493":4,"494":4}}],["🔁",{"2":{"396":2}}],["📲",{"2":{"396":2}}],["🔧",{"2":{"396":2}}],["🛎️",{"2":{"396":2}}],["📝tmp",{"2":{"114":2}}],["📝alert",{"2":{"113":1}}],["📝appcomponent",{"2":{"119":1}}],["📝app",{"2":{"102":1,"114":1}}],["📝content",{"2":{"105":3,"106":2}}],["📝parent",{"2":{"103":1,"104":2}}],["📝shadow",{"2":{"102":1}}],["📝子组件",{"2":{"95":1,"96":1,"116":3}}],["📝父组件",{"2":{"95":1,"96":1,"116":3}}],["📝model",{"2":{"13":4}}],["部署运行环境搭建",{"2":{"396":2}}],["到",{"2":{"396":2}}],["主要用于服务器端的javascript编程",{"2":{"549":1}}],["主要区别在于代码生成的方式",{"2":{"491":1}}],["主要字号字体等",{"2":{"488":1}}],["主要空隙",{"2":{"488":1}}],["主要流程",{"2":{"396":1}}],["主题色",{"2":{"488":1}}],["主线程",{"2":{"495":4}}],["主线程使用复杂的策略对布局树进行分层",{"2":{"460":1}}],["主线程会遍历得到的dom",{"2":{"458":1}}],["主线程不会等待",{"2":{"456":1}}],["主线程将任务交给其他线程去处理",{"2":{"447":1}}],["主进程负责执行",{"2":{"444":1}}],["主动向原型中添加的属性或方法",{"2":{"274":1}}],["脚本",{"0":{"395":1}}],["脚本方式",{"2":{"5":1}}],["规则",{"2":{"509":3}}],["规定排序顺序",{"2":{"388":2}}],["规范提示用户输入提交信息",{"2":{"221":1}}],["规范提交信息",{"2":{"218":1}}],["统计数组中每个元素出现的次数",{"0":{"385":1}}],["统一存储到原型中",{"2":{"275":1}}],["统一开发标准",{"2":{"149":1}}],["作为第一次调用",{"2":{"378":2}}],["作用域的一种特殊应用",{"2":{"536":1}}],["作用域内被声明",{"2":{"516":1}}],["作用和arguments基本是一致",{"2":{"264":2}}],["作用",{"2":{"132":1,"221":1,"499":1}}],["拿到所有图片的图片名称并以数组形式返回",{"0":{"374":1}}],["值就保存在变量指向的那个内存地址",{"2":{"515":1}}],["值也需相同才返回",{"2":{"512":1}}],["值只能为string",{"2":{"402":2}}],["值",{"2":{"368":2,"573":1}}],["过度使用闭包会造成内存占用过多",{"2":{"538":1}}],["过期清除",{"2":{"522":1}}],["过期时限",{"2":{"41":1}}],["过滤小于",{"0":{"362":1}}],["排除法",{"2":{"594":1}}],["排除的文件夹",{"2":{"357":2,"599":2}}],["排序动画图解",{"2":{"288":1}}],["排序算法现在是稳定的",{"2":{"387":1}}],["排序算法",{"0":{"286":1},"1":{"287":1,"288":1,"289":1,"290":1,"291":1}}],["排序",{"2":{"4":1}}],["纯前端",{"0":{"357":1}}],["给对象加上新增的文章映射",{"2":{"596":1}}],["给父元素添加display",{"2":{"482":1}}],["给父元素添加position",{"2":{"482":1}}],["给父元素添加overflow",{"2":{"482":1}}],["给父元素添加透明边框",{"2":{"482":1}}],["给用户造成卡死现象",{"2":{"447":1}}],["给原子组起别名",{"0":{"356":1}}],["给控件加上name属性",{"2":{"118":1}}],["替换练习",{"0":{"355":1}}],["替换操作",{"2":{"346":2}}],["限定不包含关键词",{"2":{"350":2}}],["限制类型在几个值之间",{"2":{"400":2}}],["限制最后一位不是数字",{"2":{"350":2}}],["限制不是",{"2":{"350":2}}],["限制speak为函数",{"2":{"144":2}}],["限制sex为字符串",{"2":{"144":4}}],["限制age为数值",{"2":{"144":4}}],["限制name必传",{"2":{"144":4}}],["限制",{"2":{"41":1}}],["符合",{"2":{"350":2}}],["批量验证密码",{"0":{"348":1}}],["批量获取投影中到组件或指令",{"2":{"106":1}}],["贪婪到最后",{"2":{"347":2}}],["贪婪匹配+",{"0":{"347":1},"1":{"348":1}}],["往少的一方倾斜",{"2":{"347":2}}],["往不存在的集合插入数据",{"2":{"2":2}}],["校验用户名",{"2":{"346":2}}],["校验规范",{"2":{"220":2}}],["式",{"2":{"345":2}}],["达到平滑动画效果",{"2":{"526":1}}],["达到跨平台无缝接轨运作",{"2":{"47":1}}],["达",{"2":{"345":2}}],["哈",{"2":{"345":4}}],["哈哈",{"2":{"265":2}}],["正",{"2":{"345":2}}],["正则表达式",{"2":{"345":2}}],["正经人谁看书啊",{"2":{"181":1}}],["匹配到一个就停止let",{"2":{"347":2}}],["匹配到的第一个",{"2":{"346":2}}],["匹配所有字母",{"2":{"345":1}}],["匹配所有字母let",{"2":{"345":1}}],["匹配所有字符",{"0":{"344":1}}],["匹配所有标点符号",{"2":{"345":2}}],["匹配完不匹配后面",{"2":{"345":2}}],["匹配文本串和模式串",{"2":{"301":2}}],["边框",{"2":{"475":1}}],["边框内圆角",{"0":{"185":1}}],["边界符^",{"0":{"342":1}}],["特殊符号放在原子表里就是普通符号",{"2":{"341":2}}],["特性",{"0":{"41":1,"497":1}}],["资料参考",{"0":{"337":1}}],["谈谈js二进制",{"2":{"336":1}}],["找了好多博客参考",{"2":{"605":1}}],["找符合",{"2":{"509":2}}],["找出素数",{"0":{"365":1}}],["找出arr1数组中",{"2":{"328":2}}],["找到项目根目录",{"2":{"563":1,"564":1}}],["找到内容本身",{"2":{"346":2}}],["找到arr",{"2":{"288":2}}],["找到这个文件位置",{"2":{"227":1}}],["找到了mycomponent组件",{"2":{"139":2,"140":1}}],["找到根元素",{"2":{"99":1}}],["属于a不属于b的元素",{"2":{"324":2}}],["属性比真实",{"2":{"560":1}}],["属性相同则后者覆盖前者",{"2":{"554":1}}],["属性为对象时只复制值",{"2":{"527":1}}],["属性会被设置为构造函数的原型对象prototype",{"2":{"498":1}}],["属性非",{"2":{"479":1}}],["属性无效",{"2":{"479":1}}],["属性来实现",{"2":{"478":1}}],["属性存取器",{"0":{"407":1},"1":{"408":1}}],["属性去修改",{"2":{"276":1}}],["属性名",{"2":{"270":4,"277":2,"404":4}}],["属性私有化",{"2":{"270":2}}],["属性设置私有",{"2":{"270":1}}],["属性设置单元格内容的垂直位置",{"2":{"174":1}}],["属性设置单元格内容的水平位置",{"2":{"174":1}}],["属性和方法",{"2":{"265":2}}],["属性的用法完全一致",{"2":{"174":2}}],["属性还可用作",{"2":{"173":1}}],["属性型",{"0":{"125":1}}],["属性型指令",{"0":{"119":1}}],["属性选择器",{"2":{"119":2,"476":1}}],["属性",{"2":{"106":2,"270":4,"274":1,"440":2}}],["属性绑定",{"0":{"86":1}}],["属性将用户信息发送给客户端",{"2":{"43":2}}],["属性发送给客户端",{"2":{"43":2}}],["属性上",{"2":{"43":2}}],["差集",{"0":{"324":1,"328":1},"2":{"324":2}}],["差集的方法",{"0":{"320":1},"1":{"321":1,"322":1,"323":1,"324":1,"325":1,"326":1,"327":1,"328":1}}],["虽然问题解决的的过程有点费劲",{"2":{"594":1}}],["虽然ts在编译时也支持代码转换",{"2":{"422":1}}],["虽然",{"2":{"322":2}}],["虽然也可以在宿主页面中放多个组件",{"2":{"82":2}}],["示例没有引入flexsearchindexoptions",{"2":{"602":1}}],["示例数组",{"2":{"321":1,"325":1}}],["示例",{"2":{"318":2,"407":1}}],["键值对以字符串形式存储",{"2":{"522":1}}],["键值对一样",{"2":{"266":2}}],["键名",{"2":{"318":2}}],["谁快用谁",{"2":{"314":1}}],["马到功成",{"2":{"308":2}}],["负责加载网络资源",{"2":{"444":1}}],["负责浏览器界面展示",{"2":{"444":1}}],["负",{"2":{"302":2}}],["负载查看",{"2":{"54":1}}],["负载查看systemctl",{"2":{"54":1}}],["仟",{"2":{"302":4}}],["佰",{"2":{"302":4}}],["拾億零壹拾萬零壹",{"2":{"302":2}}],["拾",{"2":{"302":4}}],["億零",{"2":{"302":2}}],["億",{"2":{"302":6}}],["萬",{"2":{"302":6}}],["千",{"2":{"302":6}}],["千万不要把密码加密到",{"2":{"43":2}}],["百度地图",{"2":{"350":2}}],["百度",{"2":{"350":4}}],["百度一下",{"2":{"349":4,"350":2}}],["百",{"2":{"302":6}}],["亿零",{"2":{"302":2}}],["亿",{"2":{"302":8}}],["万",{"2":{"302":8}}],["元组",{"2":{"399":1,"400":2}}],["元字符",{"0":{"343":1}}],["元",{"2":{"302":6}}],["元素默认不会触发",{"2":{"615":1}}],["元素会被移出正常文档流",{"2":{"479":1}}],["元素来实现",{"2":{"478":1}}],["元素字体大小变化",{"2":{"465":1}}],["元素尺寸或位置发生改变",{"2":{"465":1}}],["元素的大小变化",{"2":{"615":2}}],["元素的宽度和高度可以直接指定为内容区域的尺寸",{"2":{"475":1}}],["元素的位置和尺寸大小",{"2":{"465":1}}],["元素的值",{"2":{"141":1}}],["元素",{"2":{"128":2,"130":1}}],["元素中",{"2":{"99":1,"141":1}}],["玖",{"2":{"302":4}}],["捌",{"2":{"302":4}}],["柒",{"2":{"302":4}}],["陆",{"2":{"302":4}}],["伍",{"2":{"302":4}}],["肆",{"2":{"302":4}}],["叁",{"2":{"302":4}}],["贰",{"2":{"302":4}}],["壹",{"2":{"302":4}}],["零元",{"2":{"302":2}}],["零$",{"2":{"302":2}}],["零",{"2":{"302":26}}],["总结",{"2":{"586":1}}],["总的来说",{"2":{"484":1}}],["总之",{"2":{"301":1}}],["总进度",{"2":{"15":2}}],["接着去执行软连接指向的",{"2":{"563":1}}],["接收数组的当前元素并返回该元素的长度",{"2":{"392":1}}],["接下来",{"2":{"301":1}}],["接口把数据传递给其他js",{"2":{"497":1}}],["接口地址为",{"2":{"46":2}}],["接口",{"0":{"412":1},"2":{"42":2,"43":2}}],["接口服务器",{"2":{"27":2}}],["先解绑该事件",{"2":{"612":2}}],["先调用原来对应方法",{"2":{"552":1}}],["先调用对線的",{"2":{"509":1}}],["先转为",{"2":{"324":2}}],["先b筛选a中没有的",{"2":{"322":2}}],["先访问左子树",{"2":{"299":2}}],["先访问节点",{"2":{"299":1}}],["先执行一次循环体",{"2":{"260":2}}],["先执行",{"2":{"240":2}}],["链表反转",{"0":{"298":1}}],["链表头部是最久未使用的元素",{"2":{"296":2}}],["缓存也没有找到",{"2":{"450":1}}],["缓存",{"2":{"450":2}}],["缓存是",{"2":{"296":8}}],["缓存最大容量",{"2":{"296":2}}],["缓存固定大小",{"2":{"296":2}}],["归并排序合并两个有序数组",{"2":{"292":2}}],["扫描所有组",{"2":{"291":2}}],["希望执行一个动画",{"2":{"526":1}}],["希望添加新的远程库",{"2":{"211":1}}],["希尔排序",{"0":{"291":1}}],["让客户端直接",{"2":{"471":1}}],["让ide在保存文件的时候根据tsconfig",{"2":{"440":2}}],["让前端开发也变得严谨而流畅",{"2":{"425":1}}],["让初始状态只能修改一次",{"2":{"304":1}}],["让后面每一个数比较找位置并插入有序数组里",{"2":{"290":1}}],["让访问",{"2":{"22":2}}],["小于0从后面计数的原则",{"2":{"532":1}}],["小型笔记本",{"2":{"489":1}}],["小的放在左数组",{"2":{"289":2}}],["小游戏",{"2":{"161":1}}],["选中心轴索引",{"2":{"289":2}}],["选择器",{"0":{"476":1}}],["选择模块解析策略",{"2":{"440":2}}],["选择排序",{"0":{"288":1}}],["选择themes目录下的一款主题文件",{"2":{"224":1}}],["选择themes目录下的一款主题文件oh",{"2":{"224":1}}],["选择文件夹",{"2":{"357":2}}],["选择文件",{"2":{"15":2}}],["快速笔记",{"2":{"588":1}}],["快速排序",{"0":{"289":1}}],["快速停止",{"2":{"72":1}}],["交互行为相关配置",{"2":{"577":2}}],["交互式提交工具",{"2":{"218":1}}],["交互式",{"2":{"56":2}}],["交给",{"2":{"464":1}}],["交集取反",{"2":{"324":2}}],["交集",{"0":{"323":1,"327":1}}],["交换",{"2":{"288":2}}],["冒泡排序",{"0":{"287":1}}],["递归按照最后一级目录生成侧边栏",{"2":{"599":2}}],["递归方式",{"2":{"543":2}}],["递归获取文件夹下的所有文件",{"2":{"357":2}}],["递归",{"2":{"297":2}}],["递归实现",{"2":{"285":2,"300":1}}],["递归+concat",{"2":{"282":2}}],["斐波那契数列",{"0":{"285":1}}],["求两个有序数组的中位数",{"0":{"292":1}}],["求最大公约数",{"0":{"284":1}}],["求删除后还有几页",{"2":{"159":2}}],["仅限二维数组",{"2":{"282":2}}],["仅用于渲染列表用于展示",{"2":{"147":2}}],["扁平化数组",{"0":{"282":1}}],["计算机通过网络进行通信的规则",{"2":{"452":1}}],["计算机硬件没有原子钟",{"2":{"448":1}}],["计算",{"2":{"445":1,"455":1}}],["计算两个或多个数字的平均值",{"0":{"382":1}}],["计算斐波那契数列",{"2":{"281":1}}],["计算阶乘",{"0":{"281":1}}],["计时器的回调函数只能在主线程空闲时运行",{"2":{"448":1}}],["计时器",{"2":{"109":2}}],["遍历前者的属性或方法",{"2":{"554":1}}],["遍历所有的",{"2":{"548":1}}],["遍历距离起点最近的节点",{"2":{"546":1}}],["遍历到的当前元素值",{"2":{"360":2}}],["遍历每一个promise并执行",{"2":{"315":2}}],["遍历回调函数数组",{"2":{"315":4}}],["遍历字符串中的每个字符",{"2":{"279":1}}],["遍历map",{"2":{"265":2}}],["出这两个有序数组的中位数",{"2":{"292":2}}],["出完栈",{"2":{"279":2}}],["出现此错误",{"2":{"592":1}}],["出现此提示表示未配置成功",{"2":{"234":1}}],["出现在其中就匹配成功",{"2":{"341":2}}],["出现identity",{"2":{"234":1}}],["出现了偏离",{"2":{"213":2}}],["栈顶出栈的左括号",{"2":{"279":2}}],["括号匹配",{"0":{"279":1}}],["通配符",{"2":{"476":1}}],["通常可以在根目录配置环境变量",{"2":{"573":1}}],["通常使用直线",{"2":{"484":1}}],["通常使用es6的模块来写ts代码",{"2":{"430":1}}],["通常改为怪异盒模型box",{"2":{"475":1}}],["通常我们也的确这么做",{"2":{"429":1}}],["通常不会为构造函数指定返回值",{"2":{"278":1}}],["通过判断滚动的距离",{"2":{"614":2}}],["通过对",{"2":{"560":1}}],["通过require函数同步加载该模块",{"2":{"549":1}}],["通过深度优先遍历",{"2":{"547":1}}],["通过css定位显示指定位置的小图片",{"2":{"486":1}}],["通过call方法调用函数",{"2":{"262":1}}],["通过call和apply调用的函数",{"2":{"262":1}}],["通过定义一个",{"2":{"478":1}}],["通过引入装饰器模式",{"2":{"426":1}}],["通过继承可以在不修改类的情况下完成对类的扩展",{"2":{"409":1}}],["通过继承可以将其他类中的属性和方法引入到当前类中",{"2":{"409":1}}],["通过类即可直接使用",{"2":{"408":1}}],["通过类来调用",{"2":{"269":2}}],["通过提供函数实现的依次测试的所有元素",{"2":{"359":1}}],["通过利用前缀表来避免不必要的比较",{"2":{"301":3}}],["通过getter和setter方法来操作属性",{"2":{"270":2}}],["通过getter",{"2":{"270":1}}],["通过arguments",{"2":{"263":2}}],["通过bind返回的函数",{"2":{"262":1}}],["通过",{"2":{"242":2,"276":1,"478":1,"572":1}}],["通过函数调用继续返回函数的方式",{"2":{"146":1}}],["通过event",{"2":{"146":1}}],["通过onxxx属性指定事件处理函数",{"2":{"146":1}}],["修改失败`",{"2":{"610":2}}],["修改成功`",{"2":{"610":2}}],["修改themeconfig的sidebar属性",{"2":{"596":1}}],["修改webpack",{"0":{"423":1}}],["修改package",{"0":{"420":1},"2":{"418":2}}],["修改原型",{"0":{"276":1}}],["修改第一次提交信息",{"0":{"214":1}}],["直到最后一个",{"2":{"548":1}}],["直到根元素",{"2":{"528":1}}],["直到目标元素",{"2":{"528":1}}],["直到",{"2":{"479":1}}],["直到找到object对象的原型",{"2":{"275":1}}],["直白点",{"2":{"427":1}}],["直接写在类名上不生效",{"2":{"586":2}}],["直接支持es6module",{"2":{"535":1}}],["直接执行catch方法",{"2":{"529":1}}],["直接针对最高级",{"2":{"487":1}}],["直接从缓存获取资源",{"2":{"471":1}}],["直接将其设置为private将导致无法再通过对象修改其中的属性",{"2":{"407":1}}],["直接通过对象所添加的属性",{"2":{"274":1}}],["直接添加到对象中的属性",{"2":{"270":1}}],["直接回车",{"2":{"232":1}}],["直接回车ssh",{"2":{"232":1}}],["直接指定项目的位置",{"2":{"173":1}}],["直接使用之前的真实dom",{"2":{"147":2}}],["访问该子节点",{"2":{"543":1}}],["访问根节点",{"2":{"543":1}}],["访问一个对象的原型对象",{"2":{"274":1}}],["访问地址为",{"2":{"46":2}}],["旺财",{"2":{"271":2,"409":2,"410":2}}],["汪汪汪",{"2":{"271":2}}],["私有化方案",{"2":{"488":1}}],["私有化数据",{"2":{"270":1}}],["私有属性只能在类内部访问",{"2":{"270":2}}],["私钥地址host",{"2":{"235":1}}],["私钥地址",{"2":{"235":3}}],["灵活性",{"2":{"269":1}}],["灵活的背景定位",{"0":{"184":1}}],["扩大系数法",{"2":{"513":1}}],["扩展性",{"2":{"269":1}}],["扩张半径取圆角的一半",{"2":{"185":2}}],["继续解析后续的",{"2":{"456":1}}],["继续下一次循环",{"2":{"260":1}}],["继承抽象类时抽象方法必须要实现",{"2":{"411":1}}],["继承的类称为",{"2":{"271":1}}],["继承发生时",{"2":{"271":1}}],["继承",{"0":{"271":1,"409":1},"1":{"410":1},"2":{"269":1,"271":1}}],["继承和多态",{"2":{"269":1}}],["封装队列",{"0":{"493":1}}],["封装为",{"2":{"424":2}}],["封装",{"0":{"270":1,"406":1},"2":{"269":2}}],["大屏手机",{"2":{"489":1}}],["大功告成",{"2":{"303":2,"307":2,"308":2}}],["大写中文",{"2":{"302":2}}],["大的放在右数组",{"2":{"289":2}}],["大家好",{"2":{"269":2}}],["大于等于",{"2":{"194":2}}],["面试",{"0":{"575":1}}],["面试题总结与归纳",{"2":{"575":1}}],["面试题",{"2":{"512":1}}],["面试相关题",{"2":{"147":2}}],["面对对象",{"0":{"403":1},"1":{"404":1,"405":1,"406":1,"407":1,"408":1,"409":1,"410":1,"411":1,"412":1}}],["面向对象的特点",{"2":{"269":1}}],["面向对象之类",{"0":{"269":1},"1":{"270":1,"271":1,"272":1}}],["英文美国",{"2":{"268":2}}],["得到35px的空白",{"2":{"482":1}}],["得到20px的空白",{"2":{"482":1}}],["得到键值对",{"2":{"266":2}}],["得到的永远是module",{"2":{"25":1}}],["猪八戒",{"2":{"265":2,"406":6,"407":2}}],["嘻嘻",{"2":{"265":2}}],["配合其他参数一起使用",{"2":{"264":2}}],["配置完后发现打包报错",{"2":{"607":1}}],["配置中的路径和",{"2":{"572":1}}],["配置文件",{"0":{"425":1},"1":{"426":1,"427":1,"428":1,"429":1,"430":1,"431":1,"432":1,"433":1,"434":1,"435":1,"436":1,"437":1,"438":1,"439":1,"440":1}}],["配置ts编译选项",{"0":{"419":1}}],["配置信息",{"2":{"418":2}}],["配置babel",{"2":{"418":2}}],["配置webpack",{"0":{"418":1},"2":{"418":2}}],["配置参数",{"2":{"231":1}}],["配置powershell",{"0":{"226":1},"1":{"227":1,"228":1}}],["配置费力费时",{"2":{"47":1}}],["配置不一致",{"2":{"47":1}}],["配置对象",{"2":{"43":2}}],["配置",{"0":{"34":1},"2":{"42":2,"221":1,"396":4,"573":1,"590":1}}],["配置解析urlencoded请求体中间件",{"2":{"30":2}}],["构造函数原型对象的原型",{"2":{"500":1}}],["构造函数会被执行",{"2":{"498":1}}],["构造函数",{"0":{"405":1},"2":{"303":2,"304":2,"315":2,"500":1}}],["构造函数的第一行代码必须为super",{"2":{"271":2}}],["构造函数执行了~",{"2":{"269":2}}],["构造函数中指向对象实例",{"2":{"517":1}}],["构造函数中",{"2":{"262":1}}],["构建优化",{"0":{"569":1},"1":{"570":1,"571":1}}],["构建静态文件",{"2":{"396":1}}],["构建前缀表",{"2":{"301":2}}],["构建工具承担",{"0":{"149":1}}],["构建参数",{"2":{"61":2}}],["构建或删除过程中产生的仓库名和标签都为none的镜像",{"2":{"55":1}}],["死循环",{"2":{"260":2}}],["再遍历后者的属性或方法",{"2":{"554":1}}],["再对新增的每一项进行数据劫持",{"2":{"552":1}}],["再比较",{"2":{"512":1}}],["再进行比较",{"2":{"512":2}}],["再调用对線的",{"2":{"509":1}}],["再调用对泉的",{"2":{"509":1}}],["再连接数组",{"2":{"322":2}}],["再递归对比每个项是否相等",{"2":{"318":1}}],["再判断条件是否执行循环体",{"2":{"260":2}}],["再执行上面代码",{"2":{"234":1}}],["成立返回true",{"2":{"256":2}}],["成功添加上了本地搜索功能",{"2":{"600":1}}],["成功2",{"2":{"314":2}}],["成功1",{"2":{"314":2}}],["成功",{"2":{"313":2,"315":2}}],["成功状态",{"2":{"303":2,"304":2}}],["成功执行",{"2":{"239":2}}],["成功为null",{"2":{"16":2}}],["左侧菜单折叠响应式",{"0":{"584":1}}],["左右有true",{"2":{"255":2}}],["左右都为true返回true",{"2":{"255":2}}],["左中右",{"2":{"174":1}}],["逻辑或",{"2":{"255":2}}],["逻辑与",{"2":{"255":2}}],["逻辑非",{"2":{"255":2}}],["逻辑运算符",{"0":{"255":1}}],["其中",{"2":{"543":2,"544":2}}],["其中最重要且广泛的的作用就是离线资源缓存",{"2":{"496":1}}],["其余都是",{"2":{"511":1}}],["其他类型转为布尔类型",{"0":{"511":1}}],["其他类型转为字符串",{"0":{"510":1}}],["其他类型转为数字类型",{"0":{"509":1}}],["其他所有线程",{"2":{"446":1}}],["其他选项",{"2":{"440":2}}],["其他运算它先将其他值转为数字",{"2":{"251":1}}],["其组合内容表示项目运行时的结构内容",{"2":{"440":2}}],["其实早期可以通过关闭一些规则设置",{"2":{"425":1}}],["其它小写",{"2":{"132":1}}],["除了上述的情况之外",{"2":{"572":1}}],["除了以上情况",{"2":{"512":1}}],["除了falsy值",{"2":{"511":1}}],["除了never本身之外",{"2":{"400":2}}],["除了1和自身",{"2":{"365":2}}],["除了加法和其他字符串运算时",{"2":{"251":1}}],["除了本身的依赖项",{"2":{"80":2}}],["算术运算符",{"0":{"251":1}}],["观察者",{"0":{"250":1}}],["老鸡咯咯叫",{"2":{"245":2}}],["老鸡",{"2":{"245":4,"246":2}}],["老虎嗷嗷叫",{"2":{"245":2}}],["老虎",{"2":{"245":4,"246":2}}],["老牛咯咯叫",{"2":{"245":2}}],["老牛嗷嗷叫",{"2":{"245":2}}],["老牛哞哞叫",{"2":{"245":4}}],["老牛",{"2":{"245":6,"246":2}}],["老刘",{"2":{"144":2}}],["循环完成后",{"2":{"392":1}}],["循环实现",{"2":{"300":2}}],["循环三要素",{"2":{"260":2}}],["循环语句",{"0":{"260":1}}],["循环中执行异步操作",{"2":{"243":1}}],["循环上传切片",{"2":{"14":1}}],["利用闭包预先存储",{"2":{"540":1}}],["利用闭包存储实参",{"2":{"539":2}}],["利用==会进行类型转换",{"2":{"512":2}}],["利用伪元素撑开高度",{"2":{"490":1}}],["利用浏览器缓存",{"2":{"486":1}}],["利用前缀表来确定匹配的位置",{"2":{"301":1}}],["利用栈来实现括号匹配",{"2":{"279":1}}],["利用",{"2":{"243":2,"552":1}}],["利用宿主机内核",{"2":{"48":1}}],["走catch",{"2":{"239":2}}],["走then",{"2":{"239":2}}],["做一些清理工作",{"2":{"239":2}}],["做的修改合并到最近的提交中",{"2":{"213":2}}],["声明必须初始化",{"2":{"515":1}}],["声明为static的属性或方法不再属于实例",{"2":{"406":1}}],["声明模板引用变量",{"2":{"130":1}}],["声名string类型变量",{"2":{"401":2}}],["声名promise并绑定this",{"0":{"303":1}}],["声名promise",{"2":{"239":1}}],["容易造成内存泄漏",{"2":{"538":1}}],["容易形成回调地狱",{"2":{"238":1}}],["容器由视口改为该祖先",{"2":{"479":1}}],["容器内网格垂直居中",{"2":{"474":2}}],["容器内网格对齐方式",{"0":{"167":1}}],["容器中区域定义",{"0":{"170":1}}],["容器划分行列",{"0":{"165":1}}],["容器属性",{"0":{"163":1},"1":{"164":1,"165":1,"166":1,"167":1,"168":1,"169":1,"170":1}}],["容器启动后",{"2":{"61":2}}],["容器卷",{"0":{"60":1}}],["容器文件路径",{"2":{"59":2}}],["容器备份到主机",{"0":{"59":1}}],["容器名",{"2":{"56":2,"62":4,"63":2}}],["容器id或容器名",{"2":{"56":4}}],["容器id",{"2":{"55":2,"56":2,"58":4,"59":4}}],["容器",{"0":{"56":1},"1":{"57":1,"58":1,"59":1,"60":1,"63":1,"64":1,"66":1,"67":1,"68":1},"2":{"49":1,"137":2,"139":2}}],["缺点",{"2":{"238":1,"485":1}}],["编程踩坑积累与总结",{"0":{"616":1}}],["编辑框实时保存",{"2":{"520":1}}],["编辑完保存前记得去掉注释",{"2":{"235":1}}],["编码和解码需要计算资源",{"2":{"485":1}}],["编译器",{"2":{"488":1}}],["编译器默认包含当前目录和子目录下所有的typescript文件",{"2":{"439":1}}],["编译器的选项",{"2":{"414":2}}],["编译文件包含哪些文件以及排除哪些文件",{"2":{"439":1}}],["编译不报错",{"2":{"435":1}}],["编译过程中需要引入的库文件的列表",{"2":{"431":1}}],["编写tsconfig",{"2":{"418":2}}],["编写webpack配置文件",{"2":{"418":2}}],["编写配置",{"0":{"73":1}}],["编写接口",{"0":{"30":1},"1":{"31":1,"32":1}}],["管理员身份",{"2":{"234":1}}],["管道名称",{"2":{"132":1}}],["管道时",{"2":{"122":2}}],["管道",{"0":{"132":1},"2":{"78":1}}],["复制成功",{"2":{"574":2}}],["复制公钥所有内容",{"2":{"233":1}}],["复杂数据",{"2":{"4":2}}],["密码不用填",{"2":{"232":2}}],["密钥",{"2":{"43":2}}],["换浏览器后没报错",{"2":{"588":1}}],["换成自己邮箱",{"2":{"232":2}}],["换行符",{"2":{"197":1}}],["乱码问题解决方式",{"2":{"225":1}}],["钩子工具",{"2":{"218":1}}],["位部分被丢弃",{"2":{"513":1}}],["位二进制",{"2":{"507":1}}],["位于",{"2":{"450":1}}],["位于原型中",{"2":{"274":1}}],["位于对象自身中",{"2":{"274":2}}],["位于分支",{"2":{"213":2}}],["位置",{"2":{"191":1,"456":2}}],["还好碰到一篇博客解决了疑惑",{"2":{"605":1}}],["还没有解析成功",{"2":{"450":1}}],["还是",{"2":{"433":1}}],["还要负责数据的安全",{"2":{"270":1}}],["还需要修改再提交",{"2":{"213":1}}],["还可以用来指定函数中的this",{"2":{"262":1}}],["还可以元数据中声名输入",{"2":{"96":1}}],["还可能需要其他模块导出的依赖项",{"2":{"80":2}}],["暂存性死区",{"0":{"516":1},"2":{"514":1,"516":2}}],["暂存更改到stash",{"2":{"212":2}}],["暂无文章",{"2":{"12":2}}],["运算符",{"0":{"253":1}}],["运用",{"2":{"211":2}}],["运行效果和ngifelese案例一样",{"2":{"121":1}}],["运行效果和ngifelese案例一样import",{"2":{"121":1}}],["运行时一直生效后续可以引用",{"2":{"61":2}}],["运行时无效",{"2":{"61":2}}],["运行",{"2":{"25":1}}],["运行在localhost",{"2":{"21":2}}],["同源下获取所有cookie",{"2":{"523":2}}],["同源策略",{"2":{"522":1}}],["同一个类型的任务必须在一个队列",{"2":{"448":1}}],["同一个仓库关联",{"2":{"211":1}}],["同",{"2":{"402":2}}],["同步到gitee",{"2":{"396":2}}],["同步代码",{"2":{"307":4,"308":2}}],["同步更新两边代码",{"2":{"211":1}}],["同时也影响",{"2":{"573":1}}],["同时也减轻了原始服务器的负载",{"2":{"486":1}}],["同时也会删除",{"2":{"205":1}}],["同时还有any类型",{"2":{"428":1}}],["同时在stage",{"2":{"426":1}}],["同时设置",{"2":{"112":1}}],["同时使用and和or条件",{"2":{"4":1}}],["完全拷贝一份新的",{"2":{"527":1}}],["完成了",{"2":{"494":2}}],["完成合并",{"2":{"210":1}}],["完整的",{"2":{"449":1}}],["完整代码",{"0":{"315":1}}],["完整配置参考",{"2":{"231":1}}],["完整写法",{"2":{"117":2,"121":1}}],["完整形式",{"2":{"86":2}}],["填第2",{"2":{"210":2}}],["添加和配置插件",{"0":{"602":1}}],["添加如下代码",{"0":{"599":1}}],["添加label",{"2":{"578":6}}],["添加图标",{"2":{"578":4}}],["添加",{"2":{"523":2}}],["添加数据",{"2":{"523":2}}],["添加或者删除可见的dom元素",{"2":{"465":1}}],["添加一个元素到缓存中",{"2":{"296":2}}],["添加方法",{"2":{"269":2}}],["添加方法的一种方式",{"2":{"269":2}}],["添加元素",{"2":{"266":2}}],["添加私钥到ssh",{"0":{"234":1},"2":{"234":1}}],["添加安装脚本呢",{"2":{"220":2}}],["添加上游分支路径",{"2":{"209":2}}],["添加到body最后",{"2":{"113":2}}],["原数组中的每个元素依次调用一个指定方法后",{"2":{"367":1}}],["原始类型",{"2":{"506":1}}],["原始数组不发生改变",{"2":{"359":1,"367":1,"377":1}}],["原始值或对象本身",{"2":{"533":1}}],["原始值",{"2":{"261":2}}],["原子组中使用",{"2":{"346":2}}],["原子组中的原子表",{"0":{"346":1}}],["原子组2",{"2":{"346":2,"349":2}}],["原子组1",{"2":{"346":2,"349":2}}],["原子组",{"0":{"341":1},"2":{"341":2}}],["原子表",{"0":{"341":1},"2":{"341":2}}],["原生的会报错",{"2":{"311":2}}],["原则",{"2":{"276":1}}],["原型和原型链",{"0":{"499":1},"1":{"500":1}}],["原型尽量不要手动改",{"2":{"276":1}}],["原型就相当于是一个公共的区域",{"2":{"275":1}}],["原型的作用",{"2":{"275":1}}],["原型链继承",{"0":{"503":1}}],["原型链属性查找规则",{"2":{"275":1}}],["原型链的长度也不同",{"2":{"274":1}}],["原型链",{"0":{"275":1},"2":{"274":1}}],["原型对象也有原型",{"2":{"274":1}}],["原型对象也负责为对象存储属性",{"2":{"274":1}}],["原型对象中的数据",{"2":{"274":1}}],["原型对象",{"2":{"274":2}}],["原型",{"0":{"274":1},"2":{"274":1}}],["原仓库url",{"2":{"209":2}}],["原理",{"2":{"43":1,"121":1}}],["拉取上游分支更新并合并",{"2":{"209":1}}],["拉取上游分支更新并合并git",{"2":{"209":1}}],["拉取合并原仓库的更新",{"0":{"209":1}}],["拉取最新提交",{"0":{"205":1}}],["远程tag",{"2":{"207":2}}],["远程分支",{"2":{"206":2}}],["例",{"2":{"205":1,"400":2}}],["例如生成",{"2":{"548":1}}],["例如",{"2":{"147":8,"233":1,"301":1,"414":2,"465":1,"528":1,"546":1,"572":2,"573":1}}],["命令查看",{"2":{"450":1}}],["命令将提交移动到正确的分支上",{"2":{"217":1}}],["命令会替换掉原有的链接",{"2":{"211":1}}],["命令用于将远程仓库中的最新提交记录拉取到本地仓库中",{"2":{"205":1}}],["命令用于从远程仓库中拉取最新的提交记录",{"2":{"205":1}}],["命令",{"2":{"205":2,"211":1}}],["真实闪烁",{"2":{"203":2}}],["真实dom比较",{"2":{"137":1}}],["普通数组",{"0":{"321":1},"1":{"322":1,"323":1,"324":1}}],["普通值的情况",{"2":{"309":1}}],["普通闪烁",{"2":{"203":2}}],["普通写法",{"2":{"117":1}}],["闪烁效果",{"0":{"203":1}}],["紧贴底部的页脚",{"0":{"202":1}}],["满足条件的留下",{"2":{"359":1}}],["满足组合才行",{"2":{"341":2}}],["满足则执行代码",{"2":{"259":2}}],["满足下列两个条件之一",{"2":{"118":1}}],["满幅背景",{"0":{"201":1}}],["凹",{"2":{"200":1}}],["凹text",{"2":{"200":1}}],["凹凸印刷文字效果",{"0":{"200":1}}],["凸",{"2":{"200":2}}],["~",{"2":{"197":1,"211":1,"221":1,"234":2,"235":4}}],["­",{"2":{"197":2}}],["至",{"2":{"194":1}}],["毛玻璃",{"0":{"194":1}}],["染色效果",{"0":{"193":1}}],["双重循环遍历数组去重",{"2":{"316":2}}],["双侧投影",{"0":{"192":1}}],["双向绑定语法",{"2":{"116":2}}],["双向绑定",{"0":{"115":1},"1":{"116":1,"117":1,"118":1}}],["切换到输入框模式",{"2":{"610":2}}],["切换到错误分支上",{"2":{"217":1}}],["切换到正确的分支并使用",{"2":{"216":1}}],["切换分支",{"2":{"212":2}}],["切换数据库",{"2":{"1":1}}],["切换数据库show",{"2":{"1":1}}],["切除与原始元素交集部分",{"2":{"191":1}}],["进而找到",{"2":{"564":1}}],["进制",{"2":{"509":2}}],["进程",{"2":{"463":1}}],["进程操纵者是操作系统",{"2":{"443":1}}],["进程慢",{"2":{"443":1}}],["进程是操作系统分配资源的基本单位",{"2":{"443":1}}],["进程与线程",{"0":{"443":1}}],["进程号",{"2":{"72":4}}],["进行求和处理",{"2":{"539":2}}],["进行存储的",{"2":{"507":1}}],["进行判断",{"2":{"496":1}}],["进行线程间通信",{"2":{"495":1}}],["进行呈现",{"2":{"464":1}}],["进行打包",{"2":{"429":1}}],["进行水平垂直位移",{"2":{"191":1}}],["进入项目根目录",{"2":{"416":1}}],["画饼图",{"2":{"481":2}}],["画draw",{"0":{"464":1}}],["画",{"2":{"455":1}}],["画该元素相同尺寸",{"2":{"191":1}}],["画布网状满天星背景",{"0":{"178":1}}],["投影大致原理",{"2":{"191":1}}],["视频摘要",{"2":{"588":1}}],["视觉效果",{"0":{"191":1},"1":{"192":1,"193":1,"194":1,"195":1}}],["视图封装模式",{"0":{"101":1}}],["梯形",{"0":{"190":1}}],["按钮点击失效问题",{"0":{"610":1}}],["按钮内容不行变解决方案",{"2":{"189":2}}],["按最后一级目录分组",{"2":{"599":2}}],["按照",{"2":{"448":1}}],["按语言系统匹配中文",{"2":{"345":2}}],["按指定模糊半径",{"2":{"191":1}}],["按指定的",{"2":{"191":1}}],["按域名ping不通",{"2":{"64":2}}],["半椭圆",{"2":{"188":2}}],["圆角",{"0":{"188":1}}],["形成原因",{"0":{"593":1}}],["形成闭包",{"2":{"536":2}}],["形成",{"2":{"455":1,"482":2}}],["形状",{"0":{"187":1},"1":{"188":1,"189":1,"190":1}}],["形式",{"2":{"43":1}}],["斜向",{"2":{"186":2}}],["横向",{"2":{"186":2}}],["条件表达式",{"2":{"260":2}}],["条件表达式\\t3",{"2":{"260":2}}],["条件运算符",{"0":{"258":1}}],["条件3",{"2":{"247":2}}],["条件2",{"2":{"247":2}}],["条件1",{"2":{"247":2}}],["条件",{"2":{"247":2}}],["条件复杂",{"0":{"247":1}}],["条件单一",{"0":{"246":1}}],["条纹背景",{"0":{"186":1}}],["条数",{"2":{"4":1}}],["下的所有文件夹",{"2":{"599":2}}],["下一个请求的下标",{"2":{"494":2}}],["下一步填写合并提交信息",{"2":{"210":1}}],["下载构建工具",{"0":{"417":1}}],["下载镜像",{"2":{"55":2}}],["下边10px",{"2":{"184":2}}],["离右侧20px",{"2":{"184":2}}],["离线",{"2":{"158":2}}],["故摘抄以便往后快捷运用",{"2":{"181":1}}],["挺有趣的",{"2":{"181":1}}],["似乎有一点香",{"2":{"181":1}}],["看到vscode有个快捷按钮",{"2":{"607":1}}],["看了这本书知识浅显易懂",{"2":{"181":1}}],["看完这本后",{"2":{"181":1}}],["看书",{"2":{"181":1}}],["看这本书前",{"2":{"181":1}}],["揭秘",{"0":{"181":1},"1":{"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1,"190":1,"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"198":1,"199":1,"200":1,"201":1,"202":1,"203":1}}],["妙妙怪的",{"0":{"181":1},"1":{"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1,"190":1,"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"198":1,"199":1,"200":1,"201":1,"202":1,"203":1}}],["轮播闪光",{"0":{"179":1}}],["上报错",{"2":{"586":1}}],["上",{"2":{"560":1}}],["上次执行时间",{"2":{"520":2}}],["上下相连的元素",{"2":{"482":2}}],["上下文切换",{"2":{"443":1}}],["上海",{"2":{"399":2}}],["上一次调用回调返回的值",{"2":{"378":1}}],["上中下",{"2":{"174":1}}],["上传",{"2":{"46":2}}],["上传分片",{"2":{"15":2}}],["上传完成",{"2":{"14":1}}],["跟",{"2":{"174":2}}],["项目一直报",{"0":{"588":1}}],["项目",{"0":{"563":1}}],["项目使用",{"0":{"421":1}}],["项目区域定义",{"0":{"173":1}}],["项目属性",{"0":{"171":1},"1":{"172":1,"173":1,"174":1}}],["项目排列顺序",{"0":{"169":1}}],["项目相对于网格",{"2":{"168":1}}],["垂直半径",{"2":{"188":2}}],["垂直",{"2":{"168":2,"186":2}}],["水平垂直居中",{"0":{"474":1}}],["水平半径",{"2":{"188":2}}],["水平",{"2":{"168":2}}],["案例练习",{"0":{"354":1},"1":{"355":1,"356":1},"2":{"347":2}}],["案例",{"2":{"167":1,"168":1}}],["调整间距属性",{"0":{"166":1}}],["调用的路径",{"2":{"572":1}}],["调用时依次执行",{"2":{"554":1}}],["调用父类的构造函数",{"2":{"271":2}}],["调用组件的某个方法执行逻辑",{"2":{"113":2}}],["调用",{"2":{"42":2,"43":2,"113":1,"126":1,"378":1}}],["学到了码农必备技能",{"2":{"607":1}}],["学习导航",{"2":{"161":1}}],["学号等唯一值",{"2":{"147":2}}],["全等",{"2":{"512":1}}],["全部",{"2":{"158":2}}],["全局替换时粗心大意造成img",{"0":{"593":1}}],["全局对象",{"2":{"535":1}}],["全局作用域中或者普通函数中指向全局对象window",{"2":{"517":1}}],["全局匹配拿不到它每个原子组",{"2":{"349":2}}],["全局匹配",{"2":{"345":2,"346":2}}],["全局安装",{"2":{"221":2}}],["全局样式能进来",{"2":{"101":1}}],["全局中间件被执行了",{"2":{"29":4}}],["状态绑定成功",{"2":{"308":2}}],["状态保护与执行者异步捕获",{"0":{"304":1}}],["状态",{"2":{"158":2}}],["请输入",{"2":{"610":2}}],["请输入esn",{"2":{"158":2}}],["请输入名称",{"2":{"158":2}}],["请求问题",{"2":{"558":1}}],["请求再次发起",{"2":{"471":1}}],["请求体",{"2":{"453":1}}],["请求体中的数据",{"2":{"43":2}}],["请求头",{"2":{"453":1}}],["请求行",{"2":{"453":1}}],["请求报文包括四个部分",{"2":{"453":1}}],["请求报文结构",{"0":{"453":1}}],["请求",{"0":{"452":1,"454":1},"1":{"453":1},"2":{"449":2}}],["请求过程",{"2":{"449":1}}],["请求资源",{"2":{"449":1}}],["请求的状态",{"2":{"40":1}}],["请求成功",{"2":{"30":4}}],["请求路径和方式",{"2":{"22":4}}],["请求方法",{"2":{"20":2}}],["请求url",{"2":{"20":2}}],["名片",{"2":{"484":1}}],["名字去重",{"2":{"374":1}}],["名字去重const",{"2":{"374":1}}],["名字可以自己指定",{"2":{"264":2}}],["名称",{"2":{"158":2,"610":2}}],["名为ngmodelchange的输出属性",{"2":{"117":1}}],["名为ngmodel的输入属性",{"2":{"117":1}}],["序号",{"2":{"158":2}}],["列出所有本地",{"2":{"206":2,"207":2}}],["列出正在运行容器",{"2":{"56":2}}],["列表页",{"0":{"158":1}}],["页脚",{"0":{"201":1}}],["页码改变",{"2":{"157":2}}],["页面加载不出来",{"0":{"613":1}}],["页面操作触发数据更新",{"2":{"553":1}}],["页面首次渲染",{"2":{"465":1}}],["页面布局",{"2":{"445":1}}],["页面",{"2":{"111":1,"590":1}}],["搜索结果预览长度",{"2":{"602":2}}],["搜索",{"2":{"157":2,"602":2}}],["搜索镜像",{"2":{"55":2}}],["某些页面特殊需要特殊处理",{"2":{"157":2}}],["某个类或样式绑定越具体",{"2":{"92":1}}],["某个作者的文章",{"2":{"12":2}}],["回流reflow",{"0":{"465":1}}],["回调函数则等预定时间才执行",{"2":{"238":1}}],["回调函数则等预定时间才执行let",{"2":{"238":1}}],["回调函数",{"0":{"238":1},"2":{"392":1}}],["回调函数形式执行次数",{"2":{"145":1}}],["回调函数形式",{"2":{"145":4}}],["回显搜索条件",{"2":{"157":2}}],["回显开关",{"2":{"157":2}}],["场景三",{"0":{"153":1}}],["场景二",{"0":{"152":1}}],["场景一",{"0":{"151":1}}],["透传",{"2":{"150":1}}],["块级作用域",{"2":{"514":1}}],["块级元素",{"2":{"474":1}}],["块书写的选项",{"2":{"150":1}}],["块中的花括号",{"2":{"129":2}}],["代表业务逻辑层",{"2":{"553":1}}],["代表用户操作的界面",{"2":{"553":1}}],["代表数据模型",{"2":{"553":1}}],["代表设备",{"2":{"489":1}}],["代理服务器",{"2":{"149":1}}],["代码示例",{"2":{"573":1}}],["代码全部完成后再进行统一计算",{"2":{"465":1}}],["代码的执行过程可能会修改当前的dom",{"2":{"456":1}}],["代码的生成",{"2":{"440":2}}],["代码中的资源",{"2":{"449":1}}],["代码优化及复用",{"0":{"310":1}}],["代码提交到了错误的分支",{"0":{"215":1},"1":{"216":1,"217":1}}],["代码分割",{"2":{"149":1}}],["代码",{"0":{"454":1},"2":{"7":2,"137":2,"444":1,"445":1,"449":2}}],["热更新",{"2":{"149":1}}],["预览所有主题命令",{"0":{"223":1}}],["预览要删除的文件列表",{"2":{"208":2}}],["预加载等",{"2":{"149":1}}],["预处理器",{"2":{"195":1}}],["预处理",{"2":{"29":1}}],["懒加载可以避免在页面中加载不必要的图片",{"2":{"486":1}}],["懒加载",{"2":{"149":1,"486":1}}],["合并多个小图片成一张大图",{"2":{"486":1}}],["合并多次提交",{"0":{"210":1}}],["合并形成",{"2":{"455":1}}],["合并数组并遍历",{"2":{"326":2}}],["合并两个有序数组",{"2":{"292":2}}],["合并最近的",{"2":{"210":2}}],["合并单元格属性",{"0":{"172":1}}],["合并代码",{"2":{"149":1}}],["合成线程计算出每个位图在屏幕上的位置",{"2":{"464":1}}],["合成线程将信息交给",{"2":{"463":1}}],["合成",{"2":{"146":1}}],["压缩图片",{"2":{"486":1}}],["压缩代码",{"2":{"149":1,"548":1}}],["压根不会把它放进",{"2":{"129":2}}],["身份证号",{"2":{"147":2}}],["身份认证",{"0":{"39":1},"1":{"40":1,"41":1,"42":1,"43":1}}],["手机息屏策略",{"2":{"520":1}}],["手机",{"2":{"489":1}}],["手机号",{"2":{"147":2}}],["手动触发window",{"2":{"584":1}}],["手动清空可解决问题",{"2":{"538":1}}],["手动控制元素的位置和样式来实现动画效果",{"2":{"477":1}}],["手动调用",{"2":{"112":1}}],["手工设定",{"2":{"197":2}}],["最稳定的版本进行开发",{"2":{"487":1}}],["最终决定获取属性立即",{"2":{"465":1}}],["最后才发现是前端element",{"2":{"609":1}}],["最后才发现自己把图床项目设为私有的项目了",{"2":{"606":1}}],["最后发现祖先元素有transform",{"2":{"605":1}}],["最后挨个试才发现需要放在docs",{"2":{"602":1}}],["最后在找到了这个issus里大佬提供的解决方案",{"2":{"600":1}}],["最后用上了",{"2":{"594":1}}],["最后再把宇符串基于number方法转换为数字",{"2":{"509":1}}],["最后返回新对象",{"2":{"498":2}}],["最后访问节点",{"2":{"299":1}}],["最后访问右子树",{"2":{"299":1}}],["最后",{"2":{"279":1}}],["最后一个区快",{"2":{"15":2}}],["最后一个区块数据全要",{"2":{"15":2}}],["最好不要直接给prototype去赋值",{"2":{"276":1}}],["最好使用每条数据的唯一标识作为key",{"2":{"147":2}}],["界面有问题",{"2":{"147":2}}],["界面效果没问题",{"2":{"147":2}}],["逆序删除等破坏顺序操作",{"2":{"147":4}}],["逆序添加",{"2":{"147":2}}],["若为立即执行",{"2":{"519":2}}],["若不是数字则默认",{"2":{"519":2}}],["若二进制前三位是",{"2":{"507":1}}],["若命中",{"2":{"471":1}}],["若第小于有序数组的最后一个数",{"2":{"290":1}}],["若后面待插入的数大于有序数组的最后一个数",{"2":{"290":1}}],["若提示",{"2":{"234":1}}],["若报错",{"2":{"220":2}}],["若跨度为",{"2":{"172":2}}],["若删除后页数小于当前页",{"2":{"159":2}}],["若对数据进行",{"2":{"147":2}}],["若虚拟dom中内容变了",{"2":{"147":2}}],["若虚拟dom中内容没变",{"2":{"147":2}}],["则合并",{"2":{"599":2}}],["则构建出的静态文件实际上会被部署到类似于",{"2":{"573":1}}],["则继续进行合并",{"2":{"554":1}}],["则以后者的属性值为准",{"2":{"554":1}}],["则第一次",{"2":{"519":2}}],["则报错",{"2":{"516":1}}],["则是由最后的一个函数声明覆盖之前所有的声明",{"2":{"514":1}}],["则是添加一个标识对应的远程库链接",{"2":{"211":1}}],["则停止查找",{"2":{"509":2}}],["则svg更适合",{"2":{"484":1}}],["则转为固定定位",{"2":{"479":1}}],["则读取",{"2":{"450":1}}],["则会自动将其调换后截取",{"2":{"532":1}}],["则会增加到",{"2":{"448":1}}],["则会将其唤醒以绁续循环拿取任务",{"2":{"446":1}}],["则这里会报错",{"2":{"427":2}}],["则需要严格按照typescript的规则来书写",{"2":{"425":1}}],["则属性便成了只读属性无法修改",{"2":{"406":1}}],["则填",{"2":{"396":2}}],["则失败",{"2":{"359":1}}],["则表示通过",{"2":{"359":1}}],["则表示合并",{"2":{"210":2}}],["则",{"2":{"345":2,"346":2,"605":1}}],["则用m",{"2":{"345":2}}],["则收集",{"2":{"326":2}}],["则进入休眠状态",{"2":{"446":1}}],["则进入while循环",{"2":{"290":1}}],["则进行收集",{"2":{"326":2}}],["则直接比较值",{"2":{"318":2}}],["则直接返回第二个值",{"2":{"255":2}}],["则直接返回第一个值的原值1",{"2":{"255":2}}],["则加零",{"2":{"302":2}}],["则删除最久未被使用的元素",{"2":{"296":2}}],["则先删除这个节点",{"2":{"296":2}}],["则判断栈顶元素是否匹配",{"2":{"279":1}}],["则入栈",{"2":{"279":1}}],["则新的对象将会作为返回值返回",{"2":{"278":1}}],["则该值会作为new运算的返回值返回",{"2":{"278":1}}],["则返回该对象",{"2":{"498":1}}],["则返回空数组",{"2":{"359":1}}],["则返回",{"2":{"279":1,"318":1,"507":1}}],["则返回undefined",{"2":{"275":1}}],["则返回true的原值",{"2":{"255":2}}],["则使用",{"2":{"275":2}}],["则不看第二个值",{"2":{"255":2}}],["则可简写第二根网格线",{"2":{"172":2}}],["则生成新的真实dom",{"2":{"147":2}}],["则从40开始",{"2":{"4":2}}],["比较的是内存地址是否相同",{"2":{"512":1}}],["比较对象是否相等",{"2":{"318":2}}],["比较规则如下",{"2":{"147":2}}],["比完第一位则结束",{"2":{"256":2}}],["比settimeout回调函数先执行",{"2":{"238":2}}],["比如浏览器",{"2":{"560":1}}],["比如数组",{"2":{"509":1}}],["比如耗时计算",{"2":{"495":1}}],["比如head默认样式display",{"2":{"459":1}}],["比如计时器",{"2":{"447":1}}],["比如我们经常使用",{"2":{"433":1}}],["比如array",{"2":{"431":1}}],["比如vue",{"2":{"426":1}}],["比如id",{"2":{"147":2}}],["比如在使用",{"2":{"122":2}}],["比如下面这个传参",{"2":{"113":2}}],["比如",{"2":{"98":2,"112":1,"113":1,"458":2}}],["比如判断或运算",{"2":{"84":1}}],["比如ng内置",{"2":{"80":2}}],["旧虚拟dom中未找到与新虚拟dom相同的key",{"2":{"147":2}}],["旧虚拟dom中找到了与新虚拟dom相同的key",{"2":{"147":2}}],["旧虚拟dom",{"2":{"147":2}}],["旧版",{"2":{"147":1}}],["每一次循环会检查消息队列中是否有任务存在",{"2":{"446":1}}],["每一行单独处理",{"2":{"345":2}}],["每秒把页面渲染",{"2":{"445":1}}],["每个",{"2":{"548":1}}],["每个then方法都可以接收上一个promise对象的返回值",{"2":{"529":1}}],["每个任务都有一个任务类型",{"2":{"448":1}}],["每个匹配项信息",{"2":{"349":2}}],["每个组件都会进行变更检测",{"2":{"111":1}}],["每次触发事件时",{"2":{"519":2,"520":2}}],["每次打开都会有这四句提示语",{"2":{"231":1}}],["每次render都会调用",{"2":{"147":1}}],["每页数量改变",{"2":{"157":2}}],["增",{"2":{"530":1}}],["增加服务器开销",{"2":{"451":1}}],["增加复杂度",{"2":{"147":1}}],["增删改",{"2":{"108":1,"132":1,"530":1}}],["尽量不使用",{"2":{"147":1}}],["典型场景表单获取默认值",{"2":{"147":1}}],["典型场景",{"2":{"147":1}}],["关闭",{"2":{"520":2}}],["关闭客户端",{"2":{"468":1}}],["关闭的时候却是四次握手",{"2":{"468":1}}],["关闭连接",{"0":{"467":1},"1":{"468":1}}],["关闭定时器",{"2":{"147":4}}],["关系运算符",{"0":{"256":1}}],["关联多个代码托管平台",{"0":{"211":1}}],["关键字",{"2":{"172":2}}],["关于虚拟dom",{"2":{"137":1}}],["卸载组件",{"2":{"147":4}}],["订阅消息",{"2":{"147":4}}],["订阅事件",{"2":{"112":1}}],["初始态把回调函数存入数组",{"2":{"315":2}}],["初始态",{"2":{"303":2,"304":2,"315":2}}],["初始值为",{"2":{"279":1}}],["初始化画图完成后出现这个锯齿",{"0":{"581":1}}],["初始化实例",{"2":{"577":2}}],["初始化",{"2":{"418":2}}],["初始化项目",{"0":{"416":1}}],["初始化变量\\t2",{"2":{"260":2}}],["初始化并应用主题",{"0":{"224":1}}],["初始化阶段",{"2":{"147":4}}],["初始化状态",{"2":{"143":2}}],["初次渲染",{"2":{"147":4}}],["触发条件",{"2":{"396":2}}],["触发gitee自动部署",{"2":{"396":2}}],["触发gitee",{"2":{"396":1}}],["触发gh",{"2":{"396":1}}],["触发事件",{"2":{"293":2}}],["触发",{"2":{"147":8}}],["触发变更检测",{"2":{"108":2}}],["由",{"2":{"553":1}}],["由事件驱动的",{"2":{"497":1}}],["由通过测试为",{"2":{"359":1}}],["由于之前没有备份博客源码",{"2":{"607":1}}],["由于真实",{"2":{"560":1}}],["由于被内层函数引用",{"2":{"536":1}}],["由于编码和解码都需要进行大量的计算",{"2":{"485":1}}],["由于base64编码会将图片转换成文本形式",{"2":{"485":1}}],["由于base64编码后的图片是直接嵌入在html或css中的",{"2":{"485":1}}],["由于使用base64编码的图片无需额外的文件下载",{"2":{"485":1}}],["由于svg是基于矢量图形的绘图技术",{"2":{"484":1}}],["由于元素的布局信息也属于可见样式",{"2":{"466":1}}],["由于",{"2":{"448":1}}],["由于模式串出现在文本串的位置是7",{"2":{"301":1}}],["由于模式串出现在文本串的位置是5",{"2":{"301":1}}],["由于引用没有变化",{"2":{"108":1}}],["由开发人员自己创建的对象",{"2":{"278":1}}],["由浏览器提供的对象",{"2":{"278":1}}],["由es标准所定义的对象",{"2":{"278":1}}],["由外层作用域决定",{"2":{"262":1}}],["由组件内部this",{"2":{"147":4}}],["由reactdom",{"2":{"147":8}}],["等同于常量",{"2":{"515":1}}],["等属性",{"2":{"466":1}}],["等发生在合成线程",{"2":{"464":1}}],["等待主线程调度执行",{"2":{"447":1}}],["等待所有异步操作执行完毕在执行后面代码",{"2":{"243":4}}],["等诸多的任务",{"2":{"447":1}}],["等等",{"2":{"146":1}}],["等值查询",{"2":{"4":1}}],["委托给组件最外层的元素",{"2":{"146":1}}],["女",{"2":{"144":4}}],["年龄",{"2":{"144":4}}],["姓名",{"2":{"144":4}}],["且不是最后一位不是零",{"2":{"302":2}}],["且没有被子组件声明为",{"2":{"150":1}}],["且为字符串",{"2":{"144":4}}],["且会自动处理url和解压tar压缩包",{"2":{"61":2}}],["必须是字符串",{"2":{"509":2}}],["必须是函数",{"2":{"388":2}}],["必须由进程启动和管理",{"2":{"443":1}}],["必须开启experimentaldecorators",{"2":{"426":1}}],["必须调用父类的构造方法",{"2":{"405":1}}],["必须",{"2":{"360":2}}],["必须以字母结束",{"2":{"350":2}}],["必须保留一个",{"2":{"210":1}}],["必须使用的一个",{"2":{"147":2}}],["必须在路径指定",{"2":{"26":1}}],["必要性的限制",{"2":{"144":2}}],["凉爽",{"2":{"143":2}}],["炎热",{"2":{"143":2}}],["今天天气很",{"2":{"143":2}}],["控制语句",{"0":{"259":1}}],["控制的",{"2":{"141":1}}],["控制",{"2":{"141":1}}],["补充",{"0":{"141":1}}],["随机生成测试数组",{"2":{"288":1}}],["随机数生成",{"0":{"267":1}}],["随机分配主机端口映射到内部容器端口",{"2":{"56":2}}],["随后渲染到到页面",{"2":{"147":2}}],["随后替换掉页面中之前的真实dom",{"2":{"147":2}}],["随后react进行",{"2":{"147":2}}],["随后new出来该类的实例",{"2":{"140":1}}],["随后呈现在页面中",{"2":{"139":2,"140":1}}],["随后调用该函数",{"2":{"139":2}}],["之前符合的字符串",{"2":{"509":2}}],["之前",{"2":{"388":2}}],["之前的promise状态并不会影响之后的promise状态",{"2":{"308":1}}],["之前在模版中调用的组件为静态组件",{"2":{"113":1}}],["之间的随机数",{"2":{"267":2}}],["之后",{"2":{"139":2,"140":1,"210":2}}],["渲染数据",{"2":{"577":2}}],["渲染",{"2":{"449":1}}],["渲染主线程无论如何忙碌",{"2":{"466":1}}],["渲染主线程永不阻塞",{"2":{"447":1}}],["渲染主线程会进入一个无限循环",{"2":{"446":1}}],["渲染进程任务",{"0":{"445":1}}],["渲染进程启动后",{"2":{"444":1}}],["渲染进程",{"2":{"444":1}}],["渲染组件到页面",{"2":{"139":2,"140":2,"143":2,"144":2}}],["渲染虚拟dom到页面",{"2":{"137":2}}],["语句贯穿",{"2":{"440":2}}],["语句的",{"2":{"440":2}}],["语句",{"2":{"137":1}}],["语法糖",{"0":{"240":1},"1":{"241":1,"242":1,"243":1}}],["语法",{"0":{"360":1,"368":1,"378":1,"388":1,"392":1},"2":{"7":1}}],["表",{"2":{"345":2}}],["表示最新的es语法",{"2":{"440":2}}],["表示按需加载",{"2":{"418":2}}],["表示任意目录",{"2":{"414":2}}],["表示任意文件",{"2":{"414":2}}],["表示且",{"2":{"400":1}}],["表示或",{"2":{"400":1}}],["表示没有返回值",{"2":{"400":2}}],["表示元素重复并且过滤",{"2":{"364":2}}],["表示是同一个元素",{"2":{"364":2}}],["表示强制等待的意思",{"2":{"240":1}}],["表示项目的左边框距离右边框跨越",{"2":{"172":2}}],["表示跨越",{"2":{"172":2}}],["表达式值为",{"2":{"440":2}}],["表达式进行全等比较",{"2":{"259":2}}],["表达式2\\t",{"2":{"258":2}}],["表达式1",{"2":{"258":2}}],["表达式",{"2":{"137":1,"259":4,"260":2}}],["表单按钮数据提交至服务器",{"2":{"528":1}}],["表单校验",{"2":{"338":1}}],["表单元素的值存储于",{"2":{"141":1}}],["表单元素的值是完全交由组件的",{"2":{"141":1}}],["表单元素的状态并不受",{"2":{"141":1}}],["表单中使用",{"2":{"118":1}}],["表单form中双向绑定",{"0":{"118":1}}],["表单数据的中间件",{"2":{"43":2}}],["要求同时设置了",{"2":{"440":2}}],["要排除的文件",{"2":{"418":2}}],["要兼容的目标浏览器及版本",{"2":{"418":2}}],["要使用的loader",{"2":{"418":2}}],["要先在项目根目录下创建一个ts的配置文件",{"2":{"414":1}}],["要部署的分支",{"2":{"396":2}}],["要改也不要通过实例对象去改",{"2":{"276":1}}],["要看也是看视频教程和大佬博客啊",{"2":{"181":1}}],["要用赋值语句的形式+箭头函数",{"2":{"143":2}}],["要用classname",{"2":{"137":1}}],["要发送给客户端的用户信息",{"2":{"43":2}}],["要发送给客户端的",{"2":{"43":2}}],["呈现在页面上",{"2":{"137":1}}],["轻松有趣",{"2":{"181":1}}],["轻",{"2":{"137":1}}],["本来想执行git",{"2":{"607":1}}],["本身",{"2":{"500":2}}],["本身会立刻返回",{"2":{"238":2}}],["本质采用的是系统时间间隔",{"2":{"526":1}}],["本质上充当web应用程序",{"2":{"497":1}}],["本质是object类型的对象",{"2":{"137":1}}],["本地打包预览环境变量",{"2":{"573":2}}],["本地的远程分支也会被清理",{"2":{"205":1}}],["本地不存在的远程分支",{"2":{"205":1}}],["本地镜像推送到阿里云",{"2":{"55":1}}],["准备好一个",{"2":{"137":2,"139":2}}],["此外",{"2":{"484":1}}],["此过程会用到",{"2":{"463":1}}],["此时",{"2":{"479":1}}],["此时服务端未收到",{"2":{"468":1}}],["此时外部的css",{"2":{"456":1}}],["此时组件的样式是全局生效的",{"2":{"101":1}}],["此",{"2":{"326":2}}],["此值不可枚举",{"2":{"261":2}}],["此处的this是undefined",{"2":{"139":2}}],["此处一定不要写引号",{"2":{"137":2}}],["虚拟",{"0":{"560":1},"2":{"560":2}}],["虚拟dom中key的作用",{"2":{"147":2}}],["虚拟dom最终会被react转化为真实dom",{"2":{"137":1}}],["虚拟dom比较",{"2":{"137":1}}],["虚拟dom",{"0":{"137":1}}],["虚悬镜像",{"2":{"55":1}}],["避免其报错",{"2":{"135":1}}],["也不会影响",{"2":{"466":1}}],["也不会换行",{"2":{"197":2}}],["也同样因为如此",{"2":{"465":1}}],["也被包含进来",{"2":{"439":1}}],["也称为类属性",{"2":{"408":1}}],["也就携带了此偏养",{"2":{"448":1}}],["也就是运营商的",{"2":{"450":1}}],["也就是遇到import",{"2":{"432":1}}],["也就是arr",{"2":{"290":1}}],["也就不能确定item是否有bestbydate",{"2":{"135":1}}],["也可以通过for循环变量",{"2":{"263":2}}],["也可以用这个函数绑定组件中不存在的变量",{"2":{"135":1}}],["也可以用内置指令ngclass",{"2":{"90":2}}],["也无法通过call",{"2":{"262":1}}],["也是只作用于单个项目",{"2":{"174":1}}],["我们在开发环境和生产环境使用不同的",{"2":{"573":1}}],["我们在service",{"2":{"496":1}}],["我们可以将",{"2":{"573":1}}],["我们可以通过设置",{"2":{"573":1}}],["我们可以在类中定义一组读取",{"2":{"407":1}}],["我们可以使用这个函数来测试一下",{"2":{"301":1}}],["我们将文本串设置为",{"2":{"301":2}}],["我们首先计算出模式串的前缀表",{"2":{"301":1}}],["我们断定变量一定不是undefined或null",{"2":{"134":1}}],["我在飞",{"2":{"276":2}}],["我是$",{"2":{"404":2,"406":6}}],["我是静态方法",{"2":{"269":2}}],["我是",{"2":{"269":2}}],["我是传入的字符串",{"2":{"95":2}}],["保证设定的时间内只会执行一次",{"2":{"518":1}}],["保证数据请求前能正常渲染模板",{"2":{"133":1}}],["保留原来位置进行定位",{"2":{"479":1}}],["保留模版类型提示",{"2":{"424":4}}],["保留字符本意",{"2":{"341":2}}],["保持简洁",{"2":{"213":1}}],["保存数据到",{"2":{"523":2}}],["保存的只是一个指向实际数据的指针",{"2":{"515":1}}],["保存序号",{"2":{"494":2}}],["保存为文件",{"2":{"334":2}}],["保存文件",{"2":{"334":2}}],["保存文件重新打开terminal看效果",{"2":{"227":1}}],["保存",{"2":{"315":2}}],["保存重启就生效啦",{"2":{"225":1}}],["保存退出",{"2":{"210":1}}],["保存到",{"2":{"42":2}}],["保存隐私数据",{"2":{"41":1}}],["安全性",{"2":{"269":1}}],["安全链",{"0":{"133":1}}],["安装插件",{"0":{"601":1}}],["安装依赖包",{"2":{"422":1}}],["安装四个依赖",{"2":{"418":2}}],["安装nerd",{"2":{"225":1}}],["安装完",{"2":{"222":1}}],["安装winget",{"2":{"222":1}}],["安装校验脚手架",{"2":{"220":2}}],["安装命令",{"0":{"70":1}}],["安装并导入",{"2":{"43":2}}],["安装jsonwebtoken",{"2":{"43":1}}],["安装",{"0":{"222":1},"2":{"34":1}}],["截取array或string",{"2":{"132":1}}],["使result和tasks相对应",{"2":{"494":2}}],["使得对于每个有向边",{"2":{"547":1}}],["使得代码更加清晰易读",{"2":{"529":1}}],["使得代码干净整洁",{"2":{"435":1}}],["使得它们在设计",{"2":{"484":1}}],["使ngfor可以循环object或map对象",{"2":{"132":1}}],["使用scss函数计算比例",{"2":{"583":1}}],["使用stream",{"2":{"492":1}}],["使用static开头",{"2":{"408":1}}],["使用遮罩层",{"2":{"551":1}}],["使用时相当于",{"2":{"512":1}}],["使用定时器setinterval",{"2":{"492":1}}],["使用websocket技术",{"2":{"492":1}}],["使用web",{"2":{"492":1}}],["使用promise",{"2":{"492":1}}],["使用ajax及其各种高级封装的异步技术",{"2":{"492":1}}],["使用abstract开头的方法叫做抽象方法",{"2":{"411":1}}],["使用矢量图形代替位图",{"2":{"486":1}}],["使用图片cdn",{"2":{"486":1}}],["使用图片压缩工具",{"2":{"486":1}}],["使用base64编码会导致html或css文件变得非常大",{"2":{"485":1}}],["使用base64编码的图片无需考虑图片路径等问题",{"2":{"485":1}}],["使用base64编码的图片具有以下优点",{"0":{"485":1}}],["使用expires",{"2":{"471":1}}],["使用异步的方式",{"2":{"447":1}}],["使用chrome启动",{"2":{"420":2}}],["使用corejs的方式",{"2":{"418":2}}],["使用静态属性无需创建实例",{"2":{"408":1}}],["使用matchall",{"2":{"349":2}}],["使用map来存储key",{"2":{"296":2}}],["使用module",{"2":{"24":1}}],["使用示例",{"2":{"295":2,"296":1}}],["使用递归函数",{"2":{"283":2}}],["使用for循环遍历字符串",{"2":{"283":2}}],["使用数组的reverse",{"2":{"283":2}}],["使用实参来执行构造函数",{"2":{"278":1}}],["使用in运算符检查属性时",{"2":{"277":1}}],["使用index作为key是没有问题的",{"2":{"147":2}}],["使用方式",{"2":{"266":2}}],["使用后回事原来的变量立刻增加1",{"2":{"254":2}}],["使用后在拉取代码会出现",{"2":{"213":2}}],["使用陷阱",{"0":{"243":1}}],["使用此命令",{"2":{"205":1}}],["使用高斯模糊算法进行处理",{"2":{"191":1}}],["使用非空断言的两个步骤",{"2":{"134":1}}],["使用井号",{"2":{"130":1}}],["使用outlet中的value",{"2":{"114":2}}],["使用outlet中的context",{"2":{"114":2}}],["使用tem",{"2":{"114":2}}],["使用构造函数新建一个组件或指令后",{"2":{"109":1}}],["使用全局错误处理中间件",{"2":{"43":2}}],["使用",{"2":{"43":3,"46":2,"124":1,"147":1,"172":2,"213":2,"217":1,"221":1,"477":1,"478":2,"516":1,"552":1}}],["使用require",{"2":{"25":1}}],["格式化",{"2":{"218":1}}],["格式化日期",{"2":{"132":1}}],["格式化查询",{"2":{"4":2}}],["引起回流属性和方法",{"2":{"465":1}}],["引用的gitee图床图片没显示",{"0":{"606":1}}],["引用类型",{"2":{"506":1,"515":1}}],["引用类型返回",{"2":{"498":1}}],["引用值",{"2":{"261":2}}],["引用没有变化",{"2":{"132":1}}],["引入后发现之前搜索框样式没了",{"2":{"602":1}}],["引入当前目录下的图片",{"2":{"551":2}}],["引入clean插件",{"2":{"418":2}}],["引入html插件",{"2":{"418":2}}],["引入一个包",{"2":{"418":2}}],["引入babel",{"2":{"139":2}}],["引入react",{"2":{"139":2}}],["引入react核心库",{"2":{"139":2}}],["引导过程还会创建",{"2":{"82":2}}],["事实上",{"2":{"128":2}}],["事件不生效问题",{"0":{"615":1}}],["事件总线意外多次触发",{"0":{"612":1}}],["事件比confirmupdate先执行",{"2":{"610":2}}],["事件冒泡",{"2":{"528":2}}],["事件捕获",{"2":{"528":2}}],["事件捕获和冒泡机制",{"0":{"528":1}}],["事件传播过程",{"2":{"528":1}}],["事件绑定指向事件源对象",{"2":{"517":1}}],["事件监听",{"2":{"447":1}}],["事件循环是异步的实现方式",{"2":{"446":1}}],["事件循环解释",{"2":{"446":1}}],["事件循环",{"0":{"446":1}}],["事件循环机制的损耗",{"2":{"448":1}}],["事件循环机制",{"0":{"442":1},"1":{"443":1,"444":1,"445":1,"446":1,"447":1,"448":1}}],["事件处理函数",{"2":{"150":1}}],["事件处理",{"0":{"146":1}}],["事件",{"2":{"20":1,"109":2,"111":1,"112":2,"146":1,"495":1,"615":2}}],["是",{"2":{"589":2,"615":2}}],["是用来指定应用程序部署的基础",{"2":{"573":1}}],["是用来处理单个模块的转换",{"2":{"548":1}}],["是ecmascript",{"2":{"549":1}}],["是扩展",{"2":{"548":1}}],["是树的宽度",{"2":{"544":1}}],["是树的高度",{"2":{"543":1}}],["是节点数",{"2":{"543":1,"544":1}}],["是一种逐层扫描节点的算法",{"2":{"544":1}}],["是一种递归或栈的思想来遍历所有节点的算法",{"2":{"543":1}}],["是一个基于请求与响应",{"2":{"452":1}}],["是一个数组",{"2":{"264":2}}],["是一个由",{"2":{"129":2}}],["是一个分组元素",{"2":{"129":2}}],["是一个",{"2":{"128":2}}],["是异步完成的",{"2":{"465":1}}],["是指在一个promise对象上多次调用then方法",{"2":{"529":1}}],["是指其内容不受文档流影响",{"2":{"483":1}}],["是指tc39最新的es",{"2":{"429":1}}],["是指由父组件传入",{"2":{"150":1}}],["是ts编译器的配置文件",{"2":{"414":2}}],["是两个要比较的元素",{"2":{"388":1}}],["是对原数组的过滤",{"2":{"359":1}}],["是函数的方法",{"2":{"262":1}}],["是否允许编译javascript文件",{"2":{"437":1}}],["是否抛出错误",{"2":{"435":1,"436":1}}],["是否启用严格的",{"2":{"434":1}}],["是否启用实验性的es装饰器",{"2":{"426":1}}],["是否类的非undefined属性已经在构造函数里初始化",{"2":{"427":1}}],["是否移除注释",{"2":{"414":2}}],["是否检查js代码是否符合语法规范",{"2":{"414":2}}],["是否对js文件进行编译",{"2":{"414":2}}],["是否存在",{"2":{"326":2}}],["是否含有某个属性",{"2":{"277":2}}],["是否已显示",{"2":{"126":2}}],["是否连接成功",{"2":{"34":1}}],["隐式转换",{"2":{"510":1}}],["隐式类型转换",{"2":{"251":1}}],["隐式创建集合",{"2":{"2":2}}],["隐藏元素的方式",{"0":{"480":1}}],["隐藏提示语",{"0":{"231":1}}],["隐藏滚动条",{"2":{"177":2}}],["隐藏",{"2":{"126":2}}],["显示屏每毫秒刷新频率",{"2":{"526":1}}],["显示出这句话表示成功啦",{"2":{"235":1}}],["显示三行文本",{"2":{"176":2}}],["显示",{"2":{"126":2}}],["显式创建集合",{"2":{"2":2}}],["别名",{"2":{"126":2}}],["实用工具集锦",{"0":{"441":1}}],["实用网站",{"0":{"161":1}}],["实际通过调用setter方法修改name属性",{"2":{"407":2}}],["实际通过调用getter方法读取name属性",{"2":{"407":2}}],["实际渲染确有小数点问题",{"0":{"180":1}}],["实例",{"2":{"615":4}}],["实例的返回值",{"2":{"314":1}}],["实例使用",{"2":{"270":2}}],["实例方法中this就是当前实例",{"2":{"269":2}}],["实例方法",{"2":{"269":2}}],["实例上的中间件",{"2":{"29":2}}],["实参都会存储到arguments对象中",{"2":{"263":2}}],["实参需要通过一个数组传递",{"2":{"262":1}}],["实现自动生成文章左侧侧边栏",{"0":{"595":1},"1":{"596":1,"597":1,"598":1,"599":1}}],["实现模块之间的相互引用",{"2":{"535":1}}],["实现三",{"2":{"520":2}}],["实现原理",{"2":{"519":2,"520":2}}],["实现对象属性和方法的共享",{"2":{"499":1}}],["实现多个请求的并发",{"2":{"492":1}}],["实现多次接收参数最后统一处理的函数编码形式",{"2":{"146":1}}],["实现一个元素的宽高比",{"0":{"490":1}}],["实现渐变背景",{"0":{"478":1}}],["实现promise",{"0":{"314":1}}],["实现promise的all方法",{"0":{"295":1}}],["实现",{"0":{"313":1},"2":{"539":2}}],["实现resolve和reject",{"0":{"312":1}}],["实现then异步",{"0":{"306":1}}],["实现eventemitter",{"0":{"293":1}}],["实现封装的方式",{"2":{"270":2}}],["实现fn1先执行",{"0":{"241":1}}],["实现在元素后面添加",{"2":{"197":1}}],["实战中可以通过一个input属性传入模版",{"2":{"126":2}}],["起因",{"2":{"526":1}}],["起别名",{"2":{"125":2}}],["起别名后",{"2":{"124":2}}],["起始0",{"2":{"4":2}}],["展开写法",{"2":{"123":1}}],["展示stars排名前五条",{"2":{"55":2}}],["展示本地镜像",{"2":{"55":2}}],["啥都不是",{"2":{"123":4}}],["葡萄",{"2":{"123":2}}],["梨",{"2":{"123":2}}],["苹果",{"2":{"123":2}}],["🎬",{"2":{"396":2}}],["🎉deploy",{"2":{"395":2}}],["🍇",{"2":{"123":2}}],["🍐",{"2":{"123":2}}],["🍎",{"2":{"123":2}}],["🎖️结果展示",{"2":{"102":1}}],["迭代表达式的值",{"2":{"122":2}}],["迭代目标",{"2":{"122":2}}],["追踪id",{"2":{"122":2}}],["赋值给变量person",{"2":{"498":2}}],["赋值运算符",{"0":{"252":1}}],["赋值",{"2":{"118":2}}],["加入到",{"2":{"563":1,"564":1}}],["加入到消息队列的未尾排队",{"2":{"447":1}}],["加载判断样式兼容问题",{"2":{"541":2}}],["加速",{"2":{"463":1}}],["加",{"2":{"116":2,"270":2}}],["加密的秘钥",{"2":{"43":2}}],["减少了服务器的负载",{"2":{"485":1}}],["减少http请求",{"2":{"485":1}}],["减小增量",{"2":{"291":2}}],["减",{"2":{"116":2}}],["传多个",{"2":{"540":2}}],["传一个",{"2":{"540":2}}],["传参会赋值给上一次yield的的返回值",{"2":{"524":1}}],["传单",{"2":{"484":1}}],["传入的是函数对象本身",{"2":{"370":2}}],["传值并执行onrejected函数",{"2":{"315":2}}],["传值并执行onfulfilled函数",{"2":{"315":2}}],["传递事件对象",{"2":{"125":2}}],["传递出去tem",{"2":{"114":2}}],["传过未传完",{"2":{"14":1}}],["传过",{"2":{"14":1}}],["监听",{"2":{"615":2}}],["监听非",{"0":{"615":1}}],["监听焦点不在此组件时",{"2":{"610":2}}],["监听div容器的无效",{"2":{"584":2}}],["监听窗口大小",{"2":{"584":2}}],["监听窗口大小变化",{"2":{"577":2}}],["监听事件",{"2":{"577":2}}],["监听图片顶部到达视口底部",{"2":{"249":1}}],["监听滚动",{"0":{"249":1}}],["监听输入属性变化",{"2":{"126":2}}],["监听组件到output事件",{"2":{"113":2}}],["监听组件销毁事件",{"2":{"113":2}}],["监听客户端请求",{"2":{"20":1}}],["根本原因",{"2":{"513":1}}],["根文件夹列表",{"2":{"440":2}}],["根据兼容情况",{"2":{"541":2}}],["根据对象的复杂程度不同",{"2":{"274":1}}],["根据key获取值",{"2":{"265":2}}],["根据函数调用方式的不同",{"2":{"262":1}}],["根据数据创建新的真实dom",{"2":{"147":2}}],["根据指定的类型",{"2":{"113":2}}],["根组件",{"2":{"78":1,"82":2}}],["×",{"2":{"113":2}}],["而虚拟",{"2":{"560":1}}],["而深度优先遍历只需要使用递归或栈",{"2":{"545":1}}],["而深度优先遍历需要使用递归或栈来遍历节点",{"2":{"545":1}}],["而",{"2":{"491":2}}],["而如果需要制作高质量的静态图形",{"2":{"484":1}}],["而svg是基于矢量图形的绘图技术",{"2":{"484":1}}],["而无需考虑内边距和边框",{"2":{"475":1}}],["而无需在文件开头添加`",{"2":{"414":2}}],["而渲染主线程承担渲染页面",{"2":{"447":1}}],["而渲染主线程只有一个",{"2":{"447":1}}],["而module选项就是指定编译使用对应的模块系统",{"2":{"430":1}}],["而是使用import和export关键字来实现",{"2":{"549":1}}],["而是由外部资源定义的元素",{"2":{"483":1}}],["而是属于类的属性",{"2":{"406":1}}],["而是通过ts动态插入到dom中到组件",{"2":{"113":1}}],["而且提示event",{"2":{"584":2}}],["而且也不是所有浏览器都会遵守",{"2":{"388":1}}],["而且可以接收cmd传的参数",{"2":{"61":2}}],["而不需要额外的文件下载",{"2":{"485":1}}],["而不是",{"2":{"526":1}}],["而不是将",{"2":{"440":2}}],["而不是创建一个新的提交",{"2":{"213":2}}],["而不是使用的原生dom事件",{"2":{"146":1}}],["而不会执行管道的逻辑",{"2":{"132":1}}],["如使用axios",{"2":{"492":1}}],["如jquery的$",{"2":{"492":1}}],["如jpeg",{"2":{"484":1}}],["如何实现动画",{"0":{"477":1}}],["如何理解异步",{"0":{"447":1}}],["如何确保数据的安全",{"2":{"270":1}}],["如此循环往复",{"2":{"446":1}}],["如",{"2":{"430":1,"449":1,"548":1}}],["如关闭加载动画",{"2":{"239":2}}],["如下命令可以直接打开power",{"2":{"228":1}}],["如果该元素的先祖容器中存在transform特性值为非none的元素",{"2":{"605":1}}],["如果pathpice",{"2":{"599":2}}],["如果你需要从你的实际路径下查看",{"2":{"572":1}}],["如果你的应用被部署在一个子目录下",{"2":{"572":1}}],["如果两者的值是对象",{"2":{"554":1}}],["如果then方法中返回了一个promise对象",{"2":{"529":1}}],["如果then方法中抛出了异常",{"2":{"529":1}}],["如果获取的值不是原始值",{"2":{"509":1}}],["如果出现任何非有效数宇宇符",{"2":{"509":1}}],["如果执行消耗大量资源的操作也不会堵塞主线程",{"2":{"497":1}}],["如果可以直接使用缓存的就直接返回缓存不再转给服务器",{"2":{"496":1}}],["如果需要向服务器发起请求的就转给服务器",{"2":{"496":1}}],["如果需要制作交互式和复杂的图形应用程序",{"2":{"484":1}}],["如果网站中注册了service",{"2":{"496":1}}],["如果主线程解析到",{"2":{"456":2}}],["如果主线程是休眠状态",{"2":{"446":1}}],["如果还没有解析成功",{"2":{"450":1}}],["如果在声明前使用",{"2":{"516":1}}],["如果在声明属性时添加一个readonly",{"2":{"406":1}}],["如果在",{"2":{"450":1}}],["如果浏览器自身的缓存里面没有找到对应的条目",{"2":{"450":1}}],["如果嵌套层级超过",{"2":{"448":1}}],["如果使用同步的方式",{"2":{"447":1}}],["如果allowjs被设置成true",{"2":{"439":1}}],["如果指定了types",{"2":{"438":1}}],["如果指定了typeroots",{"2":{"438":1}}],["如果指明了参数",{"2":{"388":1}}],["如果设置为true",{"2":{"437":1}}],["如果设置该选项为true",{"2":{"427":1}}],["如果只是练手typescirpt",{"2":{"434":1}}],["如果遇到属于这些标准库的class或api时",{"2":{"431":1}}],["如果开启该值",{"2":{"428":1}}],["如果开启strictpropertyinitialization",{"2":{"427":2}}],["如果子类中的方法会替换掉父类中的同名方法",{"2":{"410":1}}],["如果子类中也定义了构造方法",{"2":{"405":1}}],["如果",{"2":{"388":3}}],["如果提供initialvalue",{"2":{"378":2}}],["如果没有",{"2":{"446":1}}],["如果没有提供initialvalue",{"2":{"378":2}}],["如果没有任何数组元素通过测试",{"2":{"359":1}}],["如果为",{"2":{"359":1}}],["如果想要它在每行的开头和结尾生效",{"2":{"345":2}}],["如果想终止在某个执行链的位置",{"2":{"239":1}}],["如果不同",{"2":{"318":1}}],["如果不存在这个方法",{"2":{"509":1}}],["如果不存在则返回",{"2":{"296":2}}],["如果不存在对数据的逆序添加",{"2":{"147":2}}],["如果要去重一个包含不同数据类型的数组",{"2":{"316":1}}],["如果缓存超出容量",{"2":{"296":2}}],["如果key已经存在",{"2":{"296":2}}],["如果栈为空说明所有括号都匹配",{"2":{"279":1}}],["如果字符不是括号",{"2":{"279":1}}],["如果匹配则出栈",{"2":{"279":1}}],["如果是",{"2":{"525":2}}],["如果是正式项目",{"2":{"434":1}}],["如果是0",{"2":{"302":2}}],["如果是右括号",{"2":{"279":1}}],["如果是左括号",{"2":{"279":1}}],["如果构造函数返回了一个对象",{"2":{"498":1}}],["如果构造函数返回的是一个非原始值",{"2":{"278":1}}],["如果构造函数没有显式地返回对象",{"2":{"498":1}}],["如果构造函数的返回值是一个原始值或者没有指定返回值",{"2":{"278":1}}],["如果依然没有找到",{"2":{"275":1}}],["如果原型中有",{"2":{"275":1}}],["如果对象中有",{"2":{"275":1}}],["如果传递了一个其他类型的属性名",{"2":{"265":1}}],["如果第一个值为ture",{"2":{"255":2}}],["如果安装了vs",{"2":{"228":1}}],["如果有多个函数声明",{"2":{"514":1}}],["如果有",{"2":{"217":1,"446":1}}],["如果确定只是简单的展示数据",{"2":{"147":2}}],["如果结构中还包含输入类的dom",{"2":{"147":2}}],["如果数组中的元素变化",{"2":{"132":1}}],["如果当前条目在可迭代对象中的索引号为奇数则为",{"2":{"122":2}}],["如果当前条目在可迭代对象中的索引号为偶数则为",{"2":{"122":2}}],["如果当前条目是可迭代对象中的最后一个条目则为",{"2":{"122":2}}],["如果当前条目是可迭代对象中的第一个条目则为",{"2":{"122":2}}],["如果说",{"2":{"113":1}}],["如图",{"2":{"82":2}}],["强缓存",{"2":{"471":2}}],["强行检测",{"2":{"112":2}}],["强制删除",{"2":{"56":2}}],["强制删除镜像",{"2":{"55":1}}],["强制删除镜像docker",{"2":{"55":1}}],["强制停止",{"2":{"56":2,"72":1}}],["结束索引大于0从前面计数",{"2":{"532":1}}],["结束索引大于等于",{"2":{"532":1}}],["结束边界触发",{"2":{"519":2}}],["结果都是nan",{"2":{"509":1}}],["结果",{"2":{"370":2}}],["结构",{"2":{"455":1}}],["结构型",{"0":{"126":1}}],["结构型指令",{"0":{"120":1},"1":{"121":1,"122":1,"123":1}}],["结构图",{"2":{"82":1}}],["结合使用可以实现局部变更检测",{"2":{"112":2}}],["与自定义变体不能一起用",{"0":{"587":1}}],["与生命周期钩子函数类似",{"2":{"554":1}}],["与其他模块化规范不同的是",{"2":{"549":1}}],["与其他",{"2":{"512":1}}],["与其他任何值都不相等",{"2":{"512":1}}],["与浏览器之间的代理服务器",{"2":{"497":1}}],["与渲染主线程无关",{"2":{"464":1}}],["与服务器建立连接",{"0":{"451":1},"2":{"449":1}}],["与中心轴比较",{"2":{"289":2}}],["与调用方式无关",{"2":{"262":2}}],["与",{"0":{"491":1,"532":1,"533":1,"557":1,"558":1},"2":{"112":2,"137":1,"147":2,"440":2,"474":1,"532":1}}],["与方法结合",{"2":{"84":2}}],["以便以后回顾或找到更优解",{"2":{"616":1}}],["以便它下一轮再次进行检查",{"2":{"112":2}}],["以下是使用",{"2":{"615":1}}],["以下是一些常见的",{"2":{"573":1}}],["以下的四种写法",{"2":{"495":1}}],["以及防止已失效的连接请求报文段突然又传送到了服务端",{"2":{"451":1}}],["以保证标签页之间不互相影响",{"2":{"444":1}}],["以严格模式检查每个模块",{"2":{"440":2}}],["以ts结尾的文件",{"2":{"418":2}}],["以8位数结尾",{"2":{"342":1}}],["以8位数结尾let",{"2":{"342":1}}],["以010开头",{"2":{"342":2}}],["以第一个数为有序数组",{"2":{"290":1}}],["以方法形式调用",{"2":{"262":3}}],["以函数形式调用指向window",{"2":{"262":2}}],["以函数形式调用",{"2":{"262":1}}],["以管理员身份运行",{"2":{"234":1}}],["以此来实现对代码的验证",{"2":{"218":1}}],["以内容盒为准",{"2":{"184":1}}],["以内容盒为准background",{"2":{"184":1}}],["以激活变更检测",{"2":{"113":2}}],["以最后一个为查询条件",{"2":{"4":2}}],["脏的",{"2":{"112":2}}],["包装类型",{"2":{"506":1}}],["包刷新等待时间",{"2":{"468":1}}],["包",{"2":{"468":1}}],["包会重发",{"2":{"468":1}}],["包会在编译过程中被包含进来",{"2":{"438":1}}],["包后中途可能丢失",{"2":{"468":1}}],["包含被观察的元素的信息",{"2":{"615":2}}],["包含类型声明的文件列表",{"2":{"440":2}}],["包含四个参数",{"2":{"378":4}}],["包括",{"2":{"572":1}}],["包括其他进程的线程",{"2":{"446":1}}],["包括还处在stage",{"2":{"440":2}}],["包括常规键名和",{"2":{"318":2}}],["包括它自身",{"2":{"257":2}}],["包括它子组件的",{"2":{"112":1}}],["包括app",{"2":{"113":2}}],["包裹",{"2":{"95":2}}],["他和他的子组件都不会检测了",{"2":{"112":1}}],["子组件写在created中",{"2":{"558":1}}],["子组件",{"2":{"556":2}}],["子组件不能修改检测完的父组件数据",{"2":{"111":1}}],["子构造函数原型对象指向父构造函数实例",{"2":{"503":2}}],["子元素",{"2":{"476":1}}],["子进程管理等",{"2":{"444":1}}],["子类中不能修改",{"2":{"406":2}}],["子类中可以修改",{"2":{"406":4}}],["子类中修改",{"2":{"406":1}}],["子类和对象中修改",{"2":{"406":1}}],["子类继承父类时",{"2":{"405":1}}],["子类",{"2":{"271":1}}],["子传父",{"2":{"94":1}}],["检测未被声明的变量",{"2":{"507":1}}],["检测字符串的开头或结尾",{"2":{"345":2}}],["检测组件中的值是否应该改变",{"2":{"111":1}}],["检查",{"2":{"440":2}}],["检查代码",{"2":{"396":1}}],["检查对象属性",{"2":{"277":1}}],["检查元素",{"2":{"266":2}}],["检查map中是否包含指定键",{"2":{"265":2}}],["检查两个值是否全等",{"2":{"257":2}}],["检查该视图及其子视图",{"2":{"112":2}}],["检查配置文件括号配对问题",{"2":{"73":2}}],["检查配置文件有没有问题",{"2":{"73":2}}],["检查容易的健康状态",{"2":{"61":2}}],["检查文件是否存在",{"2":{"15":2,"234":1}}],["定位到可能是浏览器插件的原因",{"2":{"588":1}}],["定位祖先元素的偏移",{"2":{"479":1}}],["定位时相对于原来位置进行定位",{"2":{"479":1}}],["定位position",{"0":{"479":1}}],["定宽内容",{"0":{"201":1}}],["定时器存在则什么都不做",{"2":{"520":2}}],["定时器回调为普通函数指向window",{"2":{"517":1}}],["定时器会触发变更检测",{"2":{"112":1}}],["定时器",{"2":{"111":1}}],["定义递归函数",{"2":{"525":2}}],["定义不同的内部状态",{"2":{"524":1}}],["定义该变量之前的区域",{"2":{"516":1}}],["定义一个对象",{"2":{"554":1}}],["定义一个平方函数",{"2":{"370":2}}],["定义一个函数",{"2":{"263":2}}],["定义三个状态",{"2":{"303":2,"304":2,"315":2}}],["定义二叉树节点类",{"2":{"299":2}}],["定义了",{"2":{"218":1}}],["定义虚拟dom时",{"2":{"137":1}}],["定义运行时环境变量",{"2":{"61":2}}],["定义",{"0":{"359":1,"367":1,"377":1,"387":1},"2":{"43":2,"126":1}}],["定义与使用全局中间件",{"2":{"29":1}}],["父组件",{"2":{"556":2}}],["父组件发生变更检测后都会调用这三个钩子",{"2":{"109":1}}],["父子相邻",{"2":{"482":1}}],["父类",{"2":{"271":1}}],["父传子",{"2":{"94":1}}],["反败为胜",{"2":{"307":4}}],["反转字符串",{"0":{"283":1}}],["反之",{"2":{"121":2,"466":1}}],["反注册该指令在全局或应用服务中注册过的所有回调",{"2":{"109":2}}],["反斜杠",{"2":{"16":1}}],["停止",{"2":{"109":2,"615":2}}],["停止nginx",{"2":{"72":1}}],["取值为百分比",{"2":{"165":1}}],["取值为数值",{"2":{"165":1}}],["取删除后的页数",{"2":{"159":2}}],["取消",{"2":{"610":2}}],["取消之前的定时器",{"2":{"519":2}}],["取消继承",{"2":{"152":2,"153":2}}],["取消订阅消息",{"2":{"147":4}}],["取消订阅可观察对象和",{"2":{"109":2}}],["取决于绑定的值是否为真",{"2":{"121":2}}],["取前中后各2各字节",{"2":{"15":2}}],["适合理一些残存的状态操作",{"2":{"109":2}}],["适合请求数据初始化组件",{"2":{"109":2}}],["适用于长",{"2":{"4":2}}],["但在其他元素上",{"2":{"615":1}}],["但值不相等",{"2":{"554":1}}],["但它们有着不同的工作原理和适用场景",{"2":{"484":1}}],["但它不会污染样式或元素布局",{"2":{"129":2}}],["但typescript不是原生的javascript代码",{"2":{"425":1}}],["但模版中使用失去类型提示",{"2":{"424":2}}],["但会发现分隔符会有乱码的问题",{"2":{"225":1}}],["但只作用于单个项目",{"2":{"174":1}}],["但效率低",{"2":{"147":2}}],["但组件内部改变输入属性是不会触发的",{"2":{"109":2}}],["但是数据没有展示",{"0":{"609":1}}],["但是线上环境访问不到",{"2":{"590":1}}],["但是折线图左侧收缩",{"2":{"584":2}}],["但是本身的标签和属性并不能直接控制其显示效果",{"2":{"483":1}}],["但是",{"2":{"448":1}}],["但是只支持简单的代码转换",{"2":{"422":1}}],["但是能直接使用tsc命令的前提时",{"2":{"414":1}}],["但是在",{"2":{"322":2}}],["但是也具有一些不同点",{"2":{"264":2}}],["但是它不是一个数组对象",{"2":{"263":2}}],["但是最终返回原值",{"2":{"255":2}}],["但是不支持es6module",{"2":{"535":1}}],["但是不支持commonjs",{"2":{"535":1}}],["但是不想新增垃圾提交信息",{"2":{"213":1}}],["但是不会自动合并",{"2":{"205":1}}],["但是不会",{"2":{"61":2}}],["但是依然会跳过onpush策略组件",{"2":{"112":1}}],["但是大多数应用只有一个组件树",{"2":{"82":2}}],["写在",{"2":{"586":1}}],["写在类名上不生效",{"2":{"586":1}}],["写或什么都不写都是public",{"2":{"406":2}}],["写法",{"2":{"495":8}}],["写法四",{"2":{"172":2}}],["写法三",{"2":{"166":2,"172":2}}],["写法二",{"2":{"166":2,"172":2,"326":2}}],["写法一",{"2":{"166":2,"172":2,"326":2}}],["写简单的逻辑和数据初始化操作",{"2":{"109":2}}],["写入到docs",{"2":{"599":2}}],["写入同一个文件",{"2":{"18":1}}],["写入成功",{"2":{"18":4}}],["写入失败",{"2":{"18":2}}],["写入文件",{"0":{"18":1}}],["生成侧边栏",{"2":{"599":2}}],["生成一级分组",{"2":{"599":2}}],["生成一个错误",{"2":{"440":2}}],["生成到一个文件中",{"2":{"440":2}}],["生成不同的文件",{"2":{"440":2}}],["生成单个",{"2":{"440":2}}],["生成相应的",{"2":{"440":4}}],["生成公钥和私钥",{"0":{"232":1}}],["生成工具",{"2":{"218":1}}],["生成",{"2":{"147":2,"267":4,"455":1,"588":1}}],["生成新镜像",{"2":{"55":1}}],["生产指定类型的组件",{"2":{"113":2}}],["生命周期钩子函数",{"2":{"109":1,"554":1}}],["生命周期函数",{"2":{"109":1}}],["生命周期",{"0":{"109":1}}],["改用iconfont文字不居中问题",{"0":{"580":1}}],["改用",{"2":{"536":2}}],["改",{"2":{"530":1}}],["改动属性造成的",{"2":{"465":1}}],["改变内部的引用类型两者都会有影响",{"2":{"527":1}}],["改变内部的引用类型两者都会有影响let",{"2":{"527":1}}],["改变",{"2":{"466":1}}],["改变状态前先判断",{"2":{"304":1}}],["改变引用",{"2":{"108":2}}],["改错分支但为未提交",{"0":{"212":1}}],["改为",{"2":{"210":1,"214":2}}],["改为yes",{"2":{"75":2}}],["keep",{"0":{"559":1}}],["keyarr",{"2":{"599":12}}],["key=",{"2":{"523":2}}],["key=value",{"2":{"523":2}}],["keyshape",{"2":{"578":22}}],["keys2",{"2":{"318":4}}],["keys1",{"2":{"318":6}}],["keys",{"2":{"265":2,"296":6,"318":6,"603":2}}],["key",{"2":{"265":19,"296":22,"318":6,"319":8,"396":6,"434":4,"523":12,"527":8,"536":8,"599":8}}],["keygen",{"2":{"232":2}}],["keyframes关键帧",{"2":{"477":1}}],["keyframes",{"2":{"179":2,"203":2}}],["key是虚拟dom对象的标识",{"2":{"147":2}}],["key最好不要用index",{"2":{"147":2}}],["key的内部原理是什么",{"2":{"147":2}}],["keyvaluepipe",{"2":{"132":1}}],["keyup",{"2":{"108":2}}],["koala",{"2":{"389":2}}],["koala=",{"2":{"389":2}}],["kind",{"2":{"357":6}}],["kill",{"2":{"56":2,"72":4}}],["know",{"2":{"347":4}}],["kmp",{"2":{"301":6}}],["kmp算法是一种高效的字符串搜索算法",{"2":{"301":3}}],["泰达米尔",{"2":{"108":2}}],["易大师",{"2":{"108":2}}],["嘉文",{"2":{"108":2}}],["赵信",{"2":{"108":2}}],["赵六",{"2":{"5":2}}],["盖伦",{"2":{"108":2}}],["赛选会飞的英雄",{"2":{"108":2}}],["即在编译时就确定模块之间的依赖关系",{"2":{"549":1}}],["即在需要使用某个模块时",{"2":{"549":1}}],["即任意两点之间都存在一条路径的最大子图",{"2":{"547":1}}],["即节点的一个线性序列",{"2":{"547":1}}],["即",{"2":{"440":2}}],["即交换参数",{"2":{"388":1}}],["即参数",{"2":{"388":1}}],["即链表尾部元素",{"2":{"296":2}}],["即可被所有实例访问",{"2":{"275":1}}],["即使单词中有换行符",{"2":{"197":2}}],["即手工在单词中插入",{"2":{"197":2}}],["即管道只会检查原始值或对象引用",{"2":{"108":1,"132":1}}],["即模版中的逻辑不能改变组件的变量",{"2":{"84":1}}],["会忽略undefined",{"2":{"527":2}}],["会忽略复合对象中的变化",{"2":{"108":1,"132":1}}],["会话结束自动清除",{"2":{"522":1}}],["会重新清除上一次定时器",{"2":{"518":1}}],["会重写父类中的run方法",{"2":{"410":2}}],["会按照科学计数法处理",{"2":{"509":1}}],["会去除",{"2":{"509":1}}],["会创建一个新的对象",{"2":{"498":2}}],["会累加15px+20px的padding",{"2":{"482":1}}],["会相互抵消15px+20px的margin",{"2":{"482":1}}],["会引发",{"2":{"465":1,"466":1}}],["会变成",{"2":{"458":2}}],["会得到一棵带有样式的dom",{"2":{"458":1}}],["会得到",{"2":{"456":1}}],["会阳塞",{"2":{"456":1}}],["会停止解析",{"2":{"456":1}}],["会启动一个预解析的线程",{"2":{"456":1}}],["会启动一个渲染主进程",{"2":{"444":1}}],["会搜索操作系统自身的",{"2":{"450":1}}],["会首先搜索浏览器自身的",{"2":{"450":1}}],["会被排列到",{"2":{"388":2}}],["会被docker",{"2":{"61":2}}],["会优先对象自身属性",{"2":{"275":1}}],["会优先访问对象自身的属性",{"2":{"274":1}}],["会添加到原型对象中的情况",{"2":{"274":1}}],["会存储到其他的对象里",{"2":{"274":1}}],["会立即执行",{"2":{"262":4}}],["会立刻返回",{"2":{"243":2}}],["会先把",{"2":{"563":1,"564":1}}],["会先进行类型转换",{"2":{"512":1}}],["会先转为布尔值后运算",{"2":{"255":2}}],["会先将其转为布尔值值再取反",{"2":{"255":2}}],["会打破异步操作并行",{"2":{"243":1}}],["会在c",{"2":{"222":1}}],["会比较方便",{"2":{"222":1}}],["会自动类型推断",{"2":{"401":2}}],["会自动将提交信息转换成符合规范的格式",{"2":{"221":1}}],["会自动启动",{"2":{"221":1}}],["会自动销毁",{"2":{"125":1}}],["会产生错误dom更新",{"2":{"147":2}}],["会产生没有必要的真实dom更新",{"2":{"147":2}}],["会报错",{"2":{"134":1,"428":1,"509":1}}],["会把",{"2":{"128":2}}],["会改变dom结构",{"2":{"121":1}}],["非对象",{"2":{"554":1}}],["非递归方式",{"2":{"543":2}}],["非标准特殊对象",{"2":{"506":1}}],["非数值与数值比较会先非数值转为数值再比较",{"2":{"256":2}}],["非布尔值运算",{"2":{"255":2}}],["非受控组件",{"2":{"141":1}}],["非空断言",{"0":{"134":1}}],["非纯管道开启方式一",{"2":{"108":2}}],["非纯管道",{"0":{"108":1}}],["非常简单",{"2":{"84":1}}],["底数",{"2":{"107":2}}],["默认设计稿的高度",{"2":{"583":2}}],["默认设计稿的宽度",{"2":{"583":2}}],["默认收缩二级节点",{"0":{"579":1}}],["默认策略",{"2":{"554":1}}],["默认策略下触发变更检测的时机",{"0":{"111":1}}],["默认为w3c",{"2":{"475":1}}],["默认每个标签页开启一个新进程",{"2":{"444":1}}],["默认是classic",{"2":{"440":2}}],["默认是false",{"2":{"414":4}}],["默认所有可见的",{"2":{"438":1}}],["默认module为",{"2":{"430":1}}],["默认情况下null和undefined是所有类型的子类型",{"2":{"399":2}}],["默认排序顺序是根据字符串",{"2":{"387":1}}],["默认使用的规范",{"2":{"218":1}}],["默认继承父组件属性",{"2":{"151":2}}],["默认值为",{"2":{"431":2}}],["默认值根据",{"2":{"430":1}}],["默认值是false",{"2":{"414":2}}],["默认值",{"2":{"116":4,"117":4,"197":2,"406":1,"414":2,"426":1,"427":1,"428":1,"429":1,"432":1,"434":1,"435":1,"436":1,"437":1,"479":1}}],["默认的管道都是纯的",{"2":{"108":1,"132":1}}],["默认只批量获取直属组件",{"2":{"106":1}}],["默认选项",{"2":{"101":1}}],["能够很好的判断数据的类型及内置对象",{"2":{"533":1}}],["能够快速地查找匹配位置",{"2":{"301":1}}],["能否接受参数转换基数",{"2":{"533":1}}],["能否修改",{"2":{"514":1}}],["能极大简化书写代码",{"2":{"426":1}}],["能多次修改状态",{"2":{"303":1}}],["能保证获取到元素",{"2":{"103":2}}],["能进能出",{"2":{"101":1}}],["标准准特殊对象",{"2":{"506":1}}],["标准普通对象",{"2":{"506":1}}],["标准盒模型",{"2":{"475":1}}],["标准并不保证这一行为",{"2":{"388":1}}],["标识栈顶元素的下标",{"2":{"279":1}}],["标识容器便于查找",{"2":{"61":2}}],["标签",{"2":{"476":1}}],["标签首字母",{"2":{"137":1}}],["标签必须闭合",{"2":{"137":1}}],["标签中混入js表达式时要用",{"2":{"137":1}}],["标签选择器投影内容",{"2":{"102":2}}],["就好了",{"2":{"594":1}}],["就需要设置base属性了",{"2":{"572":1}}],["就需要重新计算",{"2":{"466":1}}],["就形成了闭包",{"2":{"536":1}}],["就可能造成无法获取到最新的布局信息浏览器在反复权衡下",{"2":{"465":1}}],["就可以使用非空断言操作符",{"2":{"134":1}}],["就可以把解析出来的用户信息",{"2":{"43":2}}],["就极有可能导致主线程产生阻塞",{"2":{"447":1}}],["就取出第一个任务执行",{"2":{"446":1}}],["就是所有的属性值",{"2":{"427":1}}],["就传递给p的回调函数",{"2":{"314":1}}],["就放在原位",{"2":{"290":1}}],["就相当于将另一个类中的代码复制到了当前类中",{"2":{"271":1}}],["就没在意这种解决方案",{"2":{"225":1}}],["就会向本地配置的首选",{"2":{"450":1}}],["就会从顶级组件从上至下开始进行变更检测",{"2":{"111":1}}],["就会按下面的顺序在特定时刻调用这些",{"2":{"109":1}}],["就自己玩",{"2":{"101":1}}],["为基础的",{"2":{"560":1}}],["为每个层生成绘制指令",{"2":{"461":1}}],["为什么要等待一段时间在关闭连接",{"2":{"468":1}}],["为什么要进行第三次握手",{"2":{"451":1}}],["为什么连接的时候是三次握手",{"2":{"468":1}}],["为什么",{"2":{"466":1}}],["为什么遍历列表时",{"2":{"147":2}}],["为装饰器提供元数据的支持",{"2":{"440":2}}],["为null",{"2":{"275":1}}],["为实例属性进行赋值",{"2":{"269":2}}],["为了设置更精确动画时间间隔",{"2":{"526":1}}],["为了保障数据发送完再断开连接",{"2":{"468":1}}],["为了避免连续的多次操作导致布局树反复计算",{"2":{"465":1}}],["为了提高解析效率",{"2":{"456":1}}],["为了防止服务器端开启一些无用的连接",{"2":{"451":1}}],["为了在不可靠的信道上建立起可靠的连接",{"2":{"451":1}}],["为了在ts代码中使用es6中的类",{"2":{"431":1}}],["为了的高效",{"2":{"146":1}}],["为了更好的兼容性",{"2":{"146":1}}],["为属性型指令",{"2":{"123":1}}],["为止",{"2":{"99":1}}],["为服务器实例绑定",{"2":{"20":1}}],["样式覆盖",{"0":{"603":1}}],["样式或者",{"2":{"483":1}}],["样式计算",{"0":{"458":1},"2":{"455":1}}],["样式",{"2":{"445":1}}],["样式的类名指定不要用class",{"2":{"137":1}}],["样式模块化",{"0":{"100":1}}],["样式应用到组件内部的所有",{"2":{"99":1}}],["样式优先级",{"2":{"92":1}}],["才取消编辑",{"2":{"610":2}}],["才执行",{"2":{"520":2}}],["才能继续解析",{"2":{"456":1}}],["才能实现跨域",{"2":{"42":1}}],["才会去原型对象中寻找",{"2":{"274":1}}],["才会把",{"2":{"99":1}}],["祖先选择器",{"0":{"99":1}}],["类似",{"2":{"440":2}}],["类似cmd",{"2":{"61":2}}],["类名",{"2":{"404":2}}],["类名时生效",{"2":{"98":1}}],["类型检测方式",{"0":{"507":1}}],["类型的时候",{"2":{"440":2}}],["类型只能为",{"2":{"402":2}}],["类型是",{"2":{"402":2}}],["类型",{"2":{"402":2,"404":4,"431":1}}],["类型声名可省略",{"2":{"401":2}}],["类型声名",{"0":{"401":1}}],["类型断言",{"2":{"400":2}}],["类型安全的any",{"2":{"400":2}}],["类型常见用法",{"2":{"399":1}}],["类型键名",{"2":{"318":2}}],["类型转换函数$any",{"0":{"135":1}}],["类方法",{"2":{"269":2}}],["类式组件",{"0":{"140":1},"2":{"140":2}}],["类或接口",{"2":{"129":2}}],["类",{"0":{"404":1},"1":{"405":1},"2":{"99":1,"276":1,"476":1}}],["当一个元素position特性值设置为fixed时",{"2":{"605":1}}],["当需要子组件的请求需要比父组件先完成时",{"2":{"558":1}}],["当队列非空时",{"2":{"544":1}}],["当参数小于0",{"2":{"532":1}}],["当用户滚动到页面的对应位置时再加载图片",{"2":{"486":1}}],["当元素祖先的",{"2":{"479":1}}],["当对一个文档进行布局",{"2":{"475":1}}],["当命中协商缓存的时候",{"2":{"471":1}}],["当改动了可见样式后",{"2":{"466":1}}],["当进行了会影响布局树的操作后",{"2":{"465":1}}],["当其他线程完成时",{"2":{"447":1}}],["当发现变量定义但没有使用时",{"2":{"435":1}}],["当启用了strictnullchecks",{"2":{"434":1}}],["当target为es6时",{"2":{"431":1}}],["当target为es5时",{"2":{"431":1}}],["当target设置为es6时",{"2":{"430":1}}],["当编译ts代码时",{"2":{"429":1}}],["当开启noimplicitany时",{"2":{"428":2}}],["当有隐含any类型时",{"2":{"428":1}}],["当有错误时不生成编译文件",{"2":{"414":2}}],["当你使用这些库时",{"2":{"426":1}}],["当缓存超出容量时",{"2":{"296":2}}],["当我们访问对象中的属性时",{"2":{"274":1}}],["当本地仓库项同时关联",{"2":{"211":1}}],["当调用时",{"2":{"195":2}}],["当前时间",{"2":{"520":2}}],["当前请求完成的数量",{"2":{"494":2}}],["当前元素在数组中的索引",{"2":{"378":1}}],["当前元素属于的数组对象",{"2":{"360":1}}],["当前元素属于的数组对象array",{"2":{"360":1}}],["当前元素的索引值",{"2":{"360":2}}],["当前promise不能返回自己",{"2":{"311":1}}],["当前页只有一页则为1",{"2":{"159":2}}],["当前镜像构建的时候不会执行",{"2":{"61":2}}],["当状态中的数据发生变化时",{"2":{"147":2}}],["当state需要从props初始化时",{"2":{"147":1}}],["当表达式不局限于访问某个属性时",{"2":{"122":2}}],["当然写了也没有问题",{"2":{"113":1}}],["当组件",{"2":{"109":1}}],["当",{"2":{"109":1,"440":2,"465":2}}],["当某个祖先元素有",{"2":{"99":1}}],["当宿主标签上有",{"2":{"98":1}}],["它作用于构建过程中的静态文件的路径",{"2":{"573":1}}],["它会影响到所有使用了vue",{"2":{"572":1}}],["它利用xml描述二维图形",{"2":{"484":1}}],["它使用javascript在html5画布中创建像素级别的图形",{"2":{"484":1}}],["它们之间的区别如下",{"2":{"549":1}}],["它们两两组合配合使用",{"2":{"471":1}}],["它们的第一个参数就是函数的this",{"2":{"262":1}}],["它影响的只是渲染流程的最后一个",{"2":{"466":1}}],["它只能被其他类所继承不能用来创建实例",{"2":{"411":1}}],["它循环遍历传入的数组",{"2":{"392":1}}],["它接受一个数组和一个回调函数",{"2":{"392":1}}],["它的this由定义时外层作用域决定",{"2":{"262":1}}],["它的优先级就越高",{"2":{"92":1}}],["它先将其他值转为字符串",{"2":{"251":1}}],["它总是等到该promise对象resolve成功之后执行",{"2":{"240":1}}],["它不是一个指令",{"2":{"129":2}}],["它永远不会直接显示出来",{"2":{"128":2}}],["它选中的是组件模板标签",{"2":{"98":1}}],["静态定位static",{"2":{"479":1}}],["静态属性",{"0":{"408":1},"2":{"406":1,"408":2}}],["静态属性可不用",{"2":{"95":2}}],["静态方法中this指向的是当前类",{"2":{"269":2}}],["静态方法",{"2":{"269":2}}],["静态绑定",{"2":{"86":2}}],["输出相对路径",{"2":{"599":2}}],["输出结果",{"2":{"536":2}}],["输出结果都是",{"2":{"536":2}}],["输出7",{"2":{"301":1}}],["输出7let",{"2":{"301":1}}],["输出5",{"2":{"301":1}}],["输出5let",{"2":{"301":1}}],["输出",{"2":{"285":2}}],["输出被props接收以外的属性",{"2":{"153":2}}],["输出querylist数组",{"2":{"104":2}}],["输出属性",{"0":{"96":1},"2":{"94":1,"96":1}}],["输出伪终端",{"2":{"56":2}}],["输入框搜索",{"2":{"520":1}}],["输入完毕后",{"2":{"221":1}}],["输入属性和指令名设为一样",{"2":{"124":2}}],["输入属性更新时触发",{"2":{"109":2}}],["输入属性",{"0":{"95":1},"2":{"94":1}}],["输入与输出属性",{"0":{"94":1}}],["有人说是图床的问题",{"2":{"606":1}}],["有",{"2":{"514":2}}],["有效",{"2":{"584":2}}],["有效数字",{"2":{"509":2}}],["有效载荷",{"2":{"43":1}}],["有且没有过期则停止搜索解析到此结束",{"2":{"450":1}}],["有且没有过期则解析到此结束",{"2":{"450":1}}],["有未使用的参数时",{"2":{"436":1,"440":2}}],["有未使用的变量时",{"2":{"435":1,"440":2}}],["有隐含的",{"2":{"428":1}}],["有很多主题",{"2":{"222":1}}],["有多个只会获取第一个",{"2":{"105":2}}],["有问题",{"2":{"92":2}}],["绑定this",{"2":{"303":2,"304":2,"315":2}}],["绑定的表达式不能或很难指定类型时使用",{"2":{"135":1}}],["绑定组件内方法",{"2":{"130":1}}],["绑定事件",{"0":{"93":1}}],["绑定总是优先于静态属性",{"2":{"92":1}}],["绑定多个style",{"0":{"92":1}}],["绑定多个class",{"0":{"90":1}}],["绑定单个style",{"0":{"91":1}}],["绑定到ngforof",{"2":{"122":2}}],["绑定到",{"2":{"29":2}}],["啦啦啦",{"2":{"89":2}}],["单线程是异步产生的原因",{"2":{"446":1}}],["单行与多行溢出隐藏",{"0":{"176":1}}],["单个项目位置",{"0":{"174":1}}],["单个class样式绑定",{"0":{"89":1}}],["单条文档",{"2":{"5":1}}],["插件",{"2":{"221":1,"418":2}}],["插值表达式属性绑定",{"0":{"88":1}}],["插入排序",{"0":{"290":1}}],["插入换行",{"0":{"197":1}}],["插入成功",{"2":{"36":2}}],["插入数据",{"0":{"36":1}}],["插入",{"0":{"5":1,"9":1}}],["执行打包命令时",{"2":{"592":1}}],["执行完成之后执行",{"2":{"548":1}}],["执行完一个后进入下一次循环",{"2":{"446":1}}],["执行顺序是从后往前依次执行",{"2":{"548":1}}],["执行以下操作",{"2":{"544":1}}],["执行时间间隔",{"2":{"526":1}}],["执行构造函数",{"2":{"498":1}}],["执行定时器的回调函数",{"2":{"445":1}}],["执行事件处理函数",{"2":{"445":1}}],["执行全局",{"2":{"445":1}}],["执行命令",{"2":{"416":1}}],["执行数组中每个值的callback",{"2":{"378":2}}],["执行数组中每个值的函数",{"2":{"378":2}}],["执行结果",{"2":{"308":1}}],["执行set",{"2":{"234":1}}],["执行",{"2":{"234":1,"368":2,"447":1}}],["执行了reactdom",{"2":{"140":1}}],["执行秩序",{"2":{"103":2}}],["执行迅速",{"2":{"84":1}}],["执行的脚本",{"2":{"61":2}}],["内层函数作用域用到了外层函数作用域的变量",{"2":{"536":1}}],["内边距",{"2":{"475":1}}],["内部样式",{"2":{"456":1}}],["内部事件监听",{"2":{"125":2}}],["内核又把结果返回给浏览器",{"2":{"450":1}}],["内容分发网络",{"2":{"486":1}}],["内容",{"2":{"475":1}}],["内容后面的字符",{"2":{"346":2}}],["内容前面的字符",{"2":{"346":2}}],["内建对象",{"2":{"278":1}}],["内置指令ngstyle绑定",{"2":{"92":2}}],["内置模块的加载优先级是最高的",{"2":{"26":1}}],["内置模块",{"2":{"23":1}}],["内联样式",{"2":{"84":2,"476":1}}],["内联模板",{"2":{"84":2}}],["722",{"2":{"578":2}}],["73",{"2":{"578":2}}],["732",{"2":{"578":2}}],["73em",{"2":{"195":2}}],["792",{"2":{"578":2}}],["77",{"2":{"578":2}}],["7种",{"2":{"261":2}}],["708",{"2":{"578":2}}],["700",{"2":{"493":2,"494":2}}],["70",{"2":{"194":1}}],["766",{"2":{"578":2}}],["762",{"2":{"578":2}}],["768",{"2":{"489":2}}],["768px",{"2":{"489":2,"603":4}}],["76",{"2":{"194":1,"198":2,"578":2}}],["75d882",{"2":{"578":2}}],["75",{"2":{"186":2,"578":2,"585":2}}],["7",{"0":{"90":1,"257":1,"346":1,"422":1,"423":1,"432":1},"2":{"84":4,"231":2,"256":2,"282":4,"288":2,"299":10,"346":2,"365":2,"370":2,"383":4,"422":1,"432":2,"551":2,"552":1}}],["都有",{"2":{"547":1}}],["都有自己私有的程序计数器",{"2":{"443":1}}],["都没有tostring",{"2":{"533":1}}],["都是对象的方法",{"2":{"533":1}}],["都代表子线程的全局对象",{"2":{"495":1}}],["都需要写联合类型",{"2":{"434":1}}],["都需要赋有初始值",{"2":{"427":1}}],["都纠结于是",{"2":{"433":1}}],["都会对文件进行处理",{"2":{"548":1}}],["都会触发回流",{"2":{"465":1}}],["都会返回true",{"2":{"277":1}}],["都会执行的回调",{"2":{"239":2}}],["都作为组件树的根",{"2":{"82":2}}],["都可以按需引入",{"2":{"561":1}}],["都可以导入imports数组中",{"2":{"80":2}}],["都可以得到响应",{"2":{"22":2}}],["该子图所使用的布局类型",{"2":{"577":2}}],["该回调函数会在浏览器下一次重绘之前执行",{"2":{"526":1}}],["该方法需要传入一个回调函数作为参数",{"2":{"526":1}}],["该对象会继承自构造函数的原型对象",{"2":{"498":1}}],["该选项告诉编译器遇到匹配的值时",{"2":{"433":1}}],["该如何去找对应文件模块解析",{"2":{"432":1}}],["该值默认值是根据",{"2":{"431":1}}],["该元素存储在",{"2":{"392":1}}],["该排序方法会在原数组上直接进行排序",{"2":{"387":1}}],["该本地仓库已关联远程库",{"2":{"211":1}}],["该容器可以存储被ref所标识的节点",{"2":{"145":2}}],["该数组中的每个组件",{"2":{"82":2}}],["该模块用到的组件",{"2":{"78":1}}],["该模块的依赖项",{"2":{"78":1}}],["来监听元素大小变化",{"2":{"615":1}}],["来决定header",{"2":{"614":2}}],["来到了新的阵地vuepress折腾",{"2":{"607":1}}],["来配置应用的部署路径",{"2":{"573":1}}],["来确保应用在不同环境下都能够正确访问静态文件",{"2":{"573":1}}],["来修改",{"2":{"483":1}}],["来禁用自动引入",{"2":{"438":1}}],["来代替",{"2":{"433":1}}],["来看是否全部成功",{"2":{"313":2}}],["来读取属性",{"2":{"270":2}}],["来合并远程分支",{"2":{"213":2}}],["来启动的",{"2":{"82":2}}],["来认证用户身份",{"2":{"43":1}}],["宿主对象",{"2":{"278":1}}],["宿主选择器",{"0":{"98":1}}],["宿主页面",{"2":{"78":1}}],["宿主机ip",{"2":{"62":2}}],["指向同一对象",{"2":{"527":1}}],["指向新创建的对象",{"2":{"498":1}}],["指向obj",{"2":{"262":1}}],["指向objfunction",{"2":{"262":1}}],["指向声明时外层作用域的this",{"2":{"262":2}}],["指数",{"2":{"107":2}}],["指令来源于formsmodule模块",{"2":{"117":1}}],["指令与组件共有的钩子",{"2":{"109":1}}],["指令销毁前调用",{"2":{"109":2}}],["指令",{"0":{"123":1},"2":{"78":1,"105":1,"119":1,"130":1}}],["指定第二个参数存在则指向第二个参数",{"2":{"517":1}}],["指定编译文件或排除指定编译文件",{"2":{"440":2}}],["指定编译的ecmascript目标版本",{"2":{"429":1}}],["指定调试器应该找到映射文件而不是生成文件的位置",{"2":{"440":2}}],["指定调试器应该找到",{"2":{"440":2}}],["指定输出目录",{"2":{"440":2}}],["指定使用模块",{"2":{"440":2}}],["指定",{"2":{"440":4}}],["指定生成哪个模块系统代码",{"2":{"430":1}}],["指定corejs的版本",{"2":{"418":2}}],["指定环境的插件",{"2":{"418":2}}],["指定加载器",{"2":{"418":2}}],["指定要包含在编译中的库文件",{"2":{"440":2}}],["指定要loader加载的规则",{"2":{"418":2}}],["指定要使用的模块化的规范",{"2":{"414":2}}],["指定webpack打包时要使用的模块",{"2":{"418":2}}],["指定打包文件的目录",{"2":{"418":2}}],["指定打包文件所在目录",{"2":{"418":2}}],["指定入口文件",{"2":{"418":2}}],["指定被编译文件的列表",{"2":{"414":2}}],["指定为元组",{"2":{"402":2}}],["指定明确的值",{"2":{"402":2}}],["指定的类型",{"2":{"272":1}}],["指定颜色的矩形",{"2":{"191":1}}],["指定默认标签属性值",{"2":{"144":2}}],["指定容器使用什么信号",{"2":{"61":2}}],["指定容器卷",{"2":{"61":2}}],["指定元数据",{"2":{"61":2}}],["指定进入容器后的默认工作目录",{"2":{"61":2}}],["指定命令解释器",{"2":{"56":2,"61":2}}],["指定端口号并启动web服务器",{"2":{"42":2}}],["指定更新",{"2":{"7":2}}],["被继承的配置文件",{"2":{"414":2}}],["被继承的类称为",{"2":{"271":1}}],["被返回并赋值给",{"2":{"392":1}}],["被async标记的函数返回也是promise对象",{"2":{"240":1}}],["被",{"2":{"77":1}}],["把sidebarstr写入到docs",{"2":{"599":2}}],["把数组里面的每个对象合并到一个对象里面",{"2":{"599":2}}],["把数字转换成字符串",{"2":{"302":2}}],["把其变为字符串",{"2":{"509":1}}],["把对象转换为数字",{"2":{"509":1}}],["把布尔转换为数宇",{"2":{"509":1}}],["把样式复制到指定类名",{"2":{"491":4}}],["把每个元素表示为一个矩形的盒子",{"2":{"475":1}}],["把该选项设置为false",{"2":{"428":1}}],["把该视图显式标记为已更改",{"2":{"112":2}}],["把一些通用逻辑封装到装饰器中",{"2":{"426":1}}],["把仓库同步到gitee",{"2":{"396":1}}],["把静态文件push到gh",{"2":{"396":1}}],["把二维数组变字符串",{"0":{"372":1}}],["把距离为",{"2":{"291":2}}],["把自定义属性",{"2":{"249":1}}],["把第一次提交的",{"2":{"214":2}}],["把需要压缩的提交",{"2":{"210":1}}],["把item视为any类型",{"2":{"135":1}}],["把首字母大写",{"2":{"132":1}}],["把onboot=no",{"2":{"75":2}}],["把源码+配置+环境+版本打包成镜像",{"2":{"47":1}}],["日志分析器",{"0":{"74":1}}],["意义",{"2":{"65":1}}],["十三",{"0":{"315":1}}],["十二",{"0":{"314":1}}],["十一",{"0":{"313":1}}],["十",{"0":{"65":1,"312":1},"1":{"66":1,"67":1,"68":1},"2":{"302":6}}],["域名解析",{"0":{"450":1},"2":{"449":1}}],["域名互ping都能通",{"2":{"64":2}}],["域名独立",{"2":{"41":1}}],["痛点及需求",{"0":{"596":1}}],["痛点",{"2":{"64":2}}],["两者的区别",{"0":{"545":1}}],["两个操作数类型相同",{"2":{"512":1}}],["两个ip可以相互ping通",{"2":{"64":2}}],["两边数据类型不同",{"2":{"512":1}}],["两种解析方式查找文件方式不同",{"2":{"432":2}}],["两种写法",{"2":{"130":2}}],["两种传参方式",{"2":{"29":2}}],["共同节点注册",{"2":{"578":2}}],["共同点",{"2":{"533":1}}],["共安装了4个包",{"2":{"422":1}}],["共用的容器关闭",{"2":{"63":2}}],["共用网卡",{"0":{"63":1}}],["共享宿主机的ip",{"2":{"62":2}}],["端口",{"2":{"62":2}}],["新建image对象",{"2":{"551":2}}],["新建网络",{"2":{"62":2}}],["新对象更改不会影响到旧对象",{"2":{"527":1}}],["新对象的",{"2":{"498":1}}],["新项目css架构设计入手方向",{"0":{"488":1}}],["新任务会加到消息队列的未尾",{"2":{"446":1}}],["新虚拟dom",{"2":{"147":2}}],["新的虚拟dom",{"2":{"147":2}}],["新数据",{"2":{"147":2}}],["新版",{"2":{"147":1}}],["新写入的会覆盖之前内容",{"2":{"18":1}}],["组成",{"2":{"475":1}}],["组成部分",{"2":{"43":1}}],["组实例三大属性",{"0":{"142":1},"1":{"143":1,"144":1,"145":1}}],["组件漏写了",{"2":{"609":1}}],["组件化开发",{"2":{"560":1}}],["组件选项达到复用的效果",{"2":{"554":1}}],["组件自定义事件的",{"2":{"150":1}}],["组件生命周期",{"0":{"147":1}}],["组件要获取",{"2":{"141":1}}],["组件状态的影响",{"2":{"141":1}}],["组件改为属性型指令",{"2":{"119":1}}],["组件是一种特殊的指令",{"2":{"119":1}}],["组件的路径",{"2":{"573":1}}],["组件的",{"2":{"112":2}}],["组件的样式不会影响到投影内容",{"2":{"100":1}}],["组件的样式不会影响到子组件中的模板",{"2":{"100":1}}],["组件特有的钩子",{"2":{"109":1}}],["组件每次检查视图时调用",{"2":{"109":2}}],["组件每次检查内容时调用",{"2":{"109":2}}],["组件相应的视图初始化之后调用",{"2":{"109":2}}],["组件初始化",{"2":{"109":2}}],["组件销毁的时候会触发的一系列的方法",{"2":{"109":1}}],["组件更新",{"2":{"109":1}}],["组件创建",{"2":{"109":1}}],["组件",{"0":{"138":1},"1":{"139":1,"140":1,"141":1,"142":1,"143":1,"144":1,"145":1,"146":1,"147":1},"2":{"105":1,"129":2,"130":1}}],["组件投影",{"0":{"102":1},"2":{"102":2}}],["组件样式出不去",{"2":{"101":2}}],["组件样式",{"0":{"97":1},"1":{"98":1,"99":1,"100":1,"101":1}}],["组id",{"2":{"61":2}}],["96",{"2":{"578":4}}],["996",{"2":{"578":2}}],["99",{"2":{"402":2}}],["999",{"2":{"385":6}}],["9999px",{"2":{"574":2}}],["999999998",{"2":{"342":2}}],["99999999",{"2":{"340":2,"342":2}}],["9999",{"2":{"61":2,"573":2}}],["9a",{"2":{"348":2}}],["9秒后打印的",{"2":{"238":2}}],["90",{"2":{"578":2}}],["900",{"2":{"493":2,"494":2,"614":6}}],["90deg",{"2":{"195":2}}],["90px",{"2":{"189":2}}],["94",{"2":{"194":1}}],["9",{"0":{"92":1,"259":1,"349":1,"434":1},"2":{"72":1,"251":2,"288":2,"341":2,"348":2,"365":2,"370":4,"490":2,"578":4}}],["954",{"2":{"578":2}}],["95",{"2":{"15":2}}],["暴露镜像的指定端口",{"2":{"61":2}}],["落脚点",{"2":{"61":2}}],["恢复后的镜像名",{"2":{"59":2}}],["备份",{"2":{"607":1}}],["备份原型上的方法",{"2":{"552":1}}],["备份整个容器",{"2":{"59":2}}],["备份文件",{"2":{"59":2}}],["xml",{"2":{"590":3}}],["xl",{"2":{"489":1,"587":4}}],["x2=",{"2":{"478":2}}],["x1=",{"2":{"478":2}}],["x阶段",{"2":{"440":2}}],["xs",{"2":{"424":18}}],["xinxi",{"2":{"318":6,"319":10}}],["x之间的随机数",{"2":{"267":2}}],["x64",{"2":{"231":2}}],["x",{"2":{"191":1,"267":10,"274":1,"297":8,"363":4,"370":6,"389":6,"402":8,"405":2,"540":24,"577":2,"578":50,"580":2,"590":2}}],["x=",{"2":{"178":4,"478":2}}],["xhr",{"2":{"111":1}}],["x86",{"2":{"66":2}}],["xxx执行过程",{"0":{"562":1},"1":{"563":1,"564":1}}],["xxxlist",{"0":{"158":1},"2":{"158":2}}],["xxxx",{"2":{"137":2}}],["xxx",{"2":{"59":2,"61":2,"113":1,"235":6,"246":2,"247":2}}],["xargs",{"2":{"56":2,"207":2}}],["前面",{"2":{"388":1}}],["前面不是数字",{"2":{"350":2}}],["前面是href=",{"2":{"350":2}}],["前序遍历",{"2":{"299":3}}],["前一位",{"2":{"290":1}}],["前自增",{"2":{"254":2}}],["前置知识",{"0":{"136":1},"1":{"137":1}}],["前台交互启动",{"2":{"57":2}}],["前端配合",{"0":{"613":1}}],["前端项目优化",{"0":{"565":1},"1":{"566":1,"567":1,"568":1,"569":1,"570":1,"571":1}}],["前端模块化规范是为了解决前端代码复杂度",{"2":{"549":1}}],["前端模块化规范",{"0":{"549":1}}],["前端本地存储方式",{"0":{"521":1},"1":{"522":1,"523":1}}],["前端如何做到并发请求",{"0":{"492":1},"1":{"493":1,"494":1}}],["前端缓存",{"0":{"470":1},"1":{"471":1,"472":1}}],["前端两种服务器",{"2":{"27":1}}],["前端代码",{"0":{"15":1,"45":1}}],["重绘网络拓扑",{"2":{"577":2}}],["重绘repaint",{"0":{"466":1}}],["重构",{"2":{"541":2}}],["重叠",{"2":{"482":1}}],["重写函数",{"2":{"552":1}}],["重写",{"0":{"410":1},"2":{"512":2}}],["重写构造函数时",{"2":{"271":2}}],["重写构造函数",{"2":{"271":2}}],["重复任意角度条纹",{"2":{"186":2}}],["重复函数",{"2":{"165":1}}],["重复调用",{"2":{"18":1}}],["重",{"2":{"137":1}}],["重启网络",{"2":{"75":1}}],["重启网络ip",{"2":{"75":1}}],["重载配置",{"2":{"73":1}}],["重载配置nginx",{"2":{"73":1}}],["重新设为开源成功解决",{"2":{"606":1}}],["重新打开",{"2":{"520":2}}],["重新计时",{"2":{"519":2}}],["重新开启定时器开始计时",{"2":{"518":1}}],["重新检查步骤配置",{"2":{"234":1}}],["重新让我拾回看书的一些兴趣",{"2":{"181":1}}],["重新恢复容器",{"2":{"59":1}}],["重新恢复容器docker",{"2":{"59":1}}],["重新进容器",{"2":{"56":2}}],["退出while循环时",{"2":{"290":2}}],["退出但不停止",{"2":{"56":2}}],["退出",{"2":{"56":2}}],["退出登录成功",{"2":{"42":2}}],["退出登录的接口",{"2":{"42":2}}],["记录执行指令地址",{"2":{"443":1}}],["记得带版本",{"2":{"55":2}}],["记住",{"2":{"43":2}}],["没发现有相关的问题",{"2":{"605":1}}],["没写在哪个目录下存放vite",{"2":{"602":1}}],["没想到里面字体挺丰富",{"2":{"225":1}}],["没啥用建议删除",{"2":{"55":1}}],["没有警告",{"2":{"609":1}}],["没有更换刷新浏览器每次都需要做多余的判断",{"2":{"541":2}}],["没有",{"2":{"514":2}}],["没有实现则返回",{"2":{"507":1}}],["没有类型可以赋值给never类型",{"2":{"400":2}}],["没有类型是never的子类型",{"2":{"400":2}}],["没有则去原型的原型中寻找",{"2":{"275":1}}],["没有则去对象的原型中寻找",{"2":{"275":1}}],["没有则创建",{"2":{"46":2,"599":2}}],["没有文件后缀",{"2":{"235":1}}],["没有配置打开vs",{"2":{"230":1}}],["没有使用结构型指令",{"2":{"128":1}}],["没有样式能进来",{"2":{"101":1}}],["没有可见的副作用",{"2":{"84":1}}],["没有自己的ip",{"2":{"62":2}}],["没有版本号默认最新",{"2":{"55":2}}],["没有这个字段的数据排在前面",{"2":{"4":2}}],["所生成的软连接",{"2":{"563":1}}],["所以它具有无限放大和缩小不失真的优势",{"2":{"484":1}}],["所以reflow",{"2":{"466":1}}],["所以",{"2":{"456":1,"465":1,"466":1}}],["所以浏览器采用异步的方式来避免",{"2":{"447":1}}],["所以typescript包含了strictnullchecks选项来帮助我们减少对这种情况的担忧",{"2":{"434":1}}],["所以需要转换为不同的模块系统",{"2":{"430":1}}],["所以需要选择一个编译的目标版本",{"2":{"429":1}}],["所以需要配置每次powershell启动时都会执行应用主题的脚本",{"2":{"226":1}}],["所以你可以使用es6来编写ts代码",{"2":{"429":1}}],["所以kmp函数返回的结果也是7",{"2":{"301":1}}],["所以kmp函数返回的结果也是5",{"2":{"301":1}}],["所以这就意味着任何数据都可以作为参数传递",{"2":{"272":1}}],["所以不是每个变量或参数定义需要明确告知类型是什么",{"2":{"428":1}}],["所以不会执行管道的逻辑",{"2":{"108":1}}],["所以不要用",{"2":{"41":1}}],["所绑定input的值",{"2":{"118":2}}],["所有想写个脚本按照目录结构自动生产对应的映射关系",{"2":{"596":1}}],["所有echart实例尺寸尺寸改变",{"2":{"584":2}}],["所有数据类型在计算机底层都是以64位二进制存储的",{"2":{"513":1}}],["所有数据类型",{"2":{"507":1}}],["所有严格检查的总开关",{"2":{"414":2}}],["所有成功才会执行成功的回调函数",{"2":{"313":2}}],["所有的公共属性",{"2":{"275":1}}],["所有生命周期钩子函数执行顺序",{"2":{"109":1}}],["所有",{"2":{"55":2,"561":1}}],["常见高级面试题",{"0":{"550":1},"1":{"551":1}}],["常见进阶面试题",{"0":{"534":1},"1":{"535":1,"536":1,"537":1,"538":1,"539":1,"540":1,"541":1,"542":1,"543":1,"544":1,"545":1,"546":1,"547":1,"548":1,"549":1}}],["常见基础面试题",{"0":{"505":1},"1":{"506":1,"507":1,"508":1,"509":1,"510":1,"511":1,"512":1,"513":1,"514":1,"515":1,"516":1,"517":1,"518":1,"519":1,"520":1,"521":1,"522":1,"523":1,"524":1,"525":1,"526":1,"527":1,"528":1,"529":1}}],["常见的可替换元素包括",{"2":{"483":1}}],["常见的高阶函数有",{"2":{"146":1}}],["常基于",{"2":{"452":1}}],["常用的有es5",{"2":{"431":1}}],["常用",{"2":{"147":8}}],["常用命令",{"0":{"53":1},"1":{"54":1,"55":1,"56":1,"57":1,"58":1,"59":1,"60":1}}],["常量",{"2":{"43":2}}],["参考博客",{"2":{"605":1}}],["参考视频",{"2":{"468":2}}],["参考链接",{"2":{"466":1}}],["参考",{"2":{"336":2}}],["参考资料",{"0":{"336":1}}],["参考教程",{"2":{"52":1}}],["参数判断处理",{"2":{"519":2}}],["参数",{"2":{"268":2,"270":4,"404":4}}],["参数来跳过编辑提交信息的步骤",{"2":{"213":1}}],["参数或返回值是一个函数满足一个条件则为高阶函数",{"2":{"146":1}}],["参数3",{"2":{"43":2}}],["参数2",{"2":{"43":2}}],["参数1",{"2":{"43":2}}],["阿里云镜像加速",{"0":{"52":1}}],["|$",{"2":{"571":2}}],["|和",{"2":{"400":1}}],["|",{"0":{"132":1,"340":1},"2":{"51":2,"56":2,"59":2,"62":2,"72":1,"73":2,"107":4,"108":2,"113":4,"122":2,"157":2,"174":12,"207":2,"224":2,"227":2,"230":2,"302":2,"335":4,"396":2,"400":4,"424":30,"434":2}}],["||",{"2":{"12":2,"21":2,"42":2,"43":2,"114":10,"125":2,"255":6,"279":8,"297":2,"318":12,"319":2,"324":4,"357":2,"507":2,"512":1,"527":2,"577":4,"578":4}}],["yield",{"2":{"524":4,"525":6}}],["y2=",{"2":{"478":2}}],["y1=",{"2":{"478":2}}],["yanglbme",{"2":{"396":2}}],["yarn",{"2":{"396":4}}],["yml",{"2":{"396":1}}],["youtube",{"2":{"588":1}}],["you",{"2":{"234":2,"235":1}}],["your",{"2":{"234":1}}],["y=",{"2":{"178":4,"478":2}}],["yellow",{"2":{"84":2,"125":2,"481":2}}],["year",{"2":{"46":4,"268":2,"294":4}}],["y",{"2":{"51":2,"55":2,"191":1,"267":4,"274":1,"297":12,"345":2,"389":6,"402":8,"416":1,"418":2,"532":24,"577":2,"578":50,"580":4}}],["yum",{"2":{"51":8,"70":1}}],["工作原理",{"0":{"50":1}}],["集中快速管理多个容器",{"2":{"65":1}}],["集中存放镜像的场所",{"2":{"49":1}}],["集合里面也只会存在一个",{"2":{"322":2}}],["集合里面只会存在一个",{"2":{"322":2}}],["集合名称",{"2":{"7":2}}],["集合相关操作",{"0":{"2":1}}],["仓库",{"2":{"49":1,"396":2}}],["简化后",{"2":{"544":2}}],["简化",{"2":{"326":2,"539":4}}],["简化读取方式",{"2":{"270":2}}],["简单类型",{"2":{"515":1}}],["简单易用",{"2":{"485":1}}],["简单递归",{"0":{"280":1},"1":{"281":1,"282":1,"283":1,"284":1,"285":1}}],["简单理解",{"2":{"271":1}}],["简单分支",{"0":{"245":1}}],["简单的说",{"2":{"147":2}}],["简单上传文件",{"0":{"44":1},"1":{"45":1,"46":1}}],["简写",{"2":{"114":2,"174":2}}],["简写形式",{"2":{"86":2,"117":1}}],["简易的linux环境",{"2":{"49":1}}],["用非递归方式实现二叉树深度优先遍历",{"2":{"543":2}}],["用css3实现饼图",{"0":{"481":1}}],["用的443端口",{"2":{"469":1}}],["用的是80端口",{"2":{"469":1}}],["用给定函数创建新字符串",{"0":{"371":1}}],["用法类似",{"2":{"526":1}}],["用法类似viewchildren",{"2":{"106":1}}],["用法",{"0":{"361":1,"369":1,"379":1,"389":1,"393":1,"523":1},"1":{"362":1,"363":1,"364":1,"365":1,"370":1,"371":1,"372":1,"373":1,"374":1,"375":1,"380":1,"381":1,"382":1,"383":1,"384":1,"385":1,"391":1},"2":{"526":1}}],["用额外对象记录当前项",{"2":{"326":2}}],["用filter去重",{"2":{"316":2}}],["用set去重",{"2":{"316":2}}],["用",{"2":{"279":1,"477":1}}],["用p",{"2":{"270":2}}],["用来描述真实",{"2":{"560":1}}],["用来控制输出目录结构",{"2":{"440":2}}],["用来设置引用模块",{"2":{"418":2}}],["用来设置编译后的文件是否使用严格模式",{"2":{"414":2}}],["用来设置属性",{"2":{"270":2}}],["用来指定编译后文件所在的目录",{"2":{"414":2}}],["用来指定项目所用的库",{"2":{"414":2}}],["用来指定ts被编译为es的版本",{"2":{"414":2}}],["用来表示不需要被编译的文件目录",{"2":{"414":2}}],["用来表示指定哪些ts文件需要被编译",{"2":{"414":2}}],["用来检查一个对象的",{"2":{"277":2}}],["用来检查两个值的关系是否成立",{"2":{"256":2}}],["用来比较两个值是否相等",{"2":{"257":2}}],["用来渲染",{"2":{"128":2}}],["用index也是可以的",{"2":{"147":2}}],["用index作为key可能会引发的问题",{"2":{"147":2}}],["用于将对象转换成可操作的基本类型值",{"2":{"533":1}}],["用于将jsx转为js",{"2":{"139":2}}],["用于解析非相对模块名称的基目录",{"2":{"440":2}}],["用于类型检查",{"2":{"412":2}}],["用于抽取类的共同特点",{"2":{"411":1}}],["用于检查的是对象的原型链上是否有该类",{"2":{"277":1}}],["用于向已经存在的远程仓库中添加一个新的",{"2":{"211":1}}],["用于添加一个新的远程仓库",{"2":{"211":1}}],["用于支持react操作dom",{"2":{"139":2}}],["用于可能为空的引用需要使用时",{"2":{"133":1}}],["用于改变dom元素的外观或行为的指令",{"2":{"119":1}}],["用于子组件传值给父组件",{"2":{"94":1}}],["用于父组件传值给子组件",{"2":{"94":1}}],["用于指定run",{"2":{"61":2}}],["用于创建容器",{"2":{"49":1}}],["用户交互",{"2":{"444":1}}],["用户id",{"2":{"61":2}}],["用户组",{"2":{"61":2}}],["用户名",{"2":{"61":2,"396":2}}],["用户的登录状态",{"2":{"42":2}}],["用户的信息对象",{"2":{"43":2}}],["用户的信息",{"2":{"42":2}}],["用户模型",{"2":{"13":2}}],["镜像id",{"2":{"59":2}}],["镜像版本号",{"2":{"55":4}}],["镜像名",{"2":{"55":2,"62":4,"63":2}}],["镜像创建出来的虚拟化运行环境容器实例",{"2":{"49":1}}],["镜像",{"0":{"55":1},"2":{"49":1}}],["镜像小",{"2":{"48":1}}],["基本类型忽略",{"2":{"498":1}}],["基本选项",{"2":{"440":2}}],["基本上没有浏览器原生支持es6的模块系统",{"2":{"430":1}}],["基本配置",{"0":{"413":1},"1":{"414":1,"415":1,"416":1,"417":1,"418":1,"419":1,"420":1,"421":1,"422":1,"423":1}}],["基本思路",{"2":{"318":1}}],["基本数据类型",{"0":{"316":1}}],["基本概念",{"0":{"162":1}}],["基本双向绑定",{"0":{"116":1}}],["基本组成",{"0":{"49":1}}],["基于es6module规范",{"2":{"535":1}}],["基于",{"2":{"516":1}}],["基于web",{"2":{"497":1}}],["基于当前镜像的镜像去构建的时候才会在from后执行",{"2":{"61":2}}],["基于什么镜像什么版本作为模版",{"2":{"61":2}}],["基础类型",{"0":{"398":1},"1":{"399":1,"400":1}}],["基础语法",{"0":{"397":1},"1":{"398":1,"399":1,"400":1,"401":1,"402":1}}],["基础命令",{"0":{"72":1}}],["基础镜像",{"2":{"61":2}}],["基础模型",{"2":{"13":2}}],["更多无限可能",{"2":{"497":1}}],["更多配置可查看官网配置文档",{"2":{"229":1}}],["更好的页面性能",{"2":{"485":1}}],["更像是",{"2":{"129":2}}],["更快的应用交付和平缓迁移",{"2":{"48":1}}],["更高效的计算资源",{"2":{"48":1}}],["更简单的系统运维",{"2":{"48":1}}],["更新表达式",{"2":{"260":2}}],["更新阶段",{"2":{"147":4}}],["更新成功",{"2":{"37":4}}],["更新数据",{"0":{"37":1}}],["更新匹配到的所有",{"2":{"7":2}}],["更新匹配到的第一条db",{"2":{"7":1}}],["更新匹配到的第一条",{"2":{"7":3}}],["更新多条",{"2":{"7":2}}],["更新",{"0":{"7":1,"11":1}}],["便捷升级和快速扩容",{"2":{"48":1}}],["便捷形式",{"2":{"36":2,"37":2}}],["处不同的提交",{"2":{"213":2}}],["处理数据",{"2":{"577":4}}],["处理数组类型",{"2":{"318":1}}],["处理完",{"2":{"520":2}}],["处理完一个就关闭连接",{"2":{"40":1}}],["处理渲染",{"2":{"449":1}}],["处理图层",{"2":{"445":1}}],["处理方式二",{"2":{"400":2}}],["处理方式一",{"2":{"400":2}}],["处理朴素对象",{"2":{"318":1}}],["处理特殊情况",{"2":{"318":1}}],["处理函数4",{"2":{"247":2}}],["处理函数2",{"2":{"247":2}}],["处理函数1",{"2":{"247":2}}],["处理映射",{"2":{"247":2}}],["处理也复杂",{"0":{"247":1}}],["处理不同",{"0":{"246":1}}],["处理代码兼容性",{"2":{"149":1}}],["处处运行",{"2":{"47":1}}],["装载在dokcer容器引擎上",{"2":{"47":1}}],["判断程序没有执行完就将本次结果传入下一步进入下一次递归",{"2":{"525":2}}],["判断当前是否存在等待执行的延时函数",{"2":{"520":2}}],["判断函数的参数是否存在",{"2":{"512":1}}],["判断对象的属性是否存在",{"2":{"512":1}}],["判断过程",{"2":{"471":1}}],["判断前面内容是",{"2":{"350":2}}],["判断新数组不存在当前项",{"2":{"326":2}}],["判断目标资源是否命中",{"2":{"471":1}}],["判断目标在数组中相同的",{"2":{"326":2}}],["判断目录是否存在",{"2":{"46":2}}],["判断数组是否相等",{"2":{"318":2}}],["判断数组长度",{"2":{"313":2}}],["判断基本类型是否相等",{"2":{"318":2}}],["判断",{"2":{"318":2,"350":2,"559":2}}],["判断类型是否一致",{"2":{"318":2}}],["判断参数是否为函数",{"2":{"315":2}}],["判断并处理返回值",{"2":{"309":4}}],["判断并分别处理返回值为promise",{"2":{"309":1}}],["判断是否是文件夹",{"2":{"599":2}}],["判断是否所有的请求都已完成",{"2":{"494":2}}],["判断是否为对象",{"2":{"316":2}}],["判断是否为最后一条数据",{"2":{"159":2}}],["判断是不是初始态",{"2":{"304":4}}],["判断合并后的数组长度",{"2":{"292":2}}],["判断用户提交的登录信息是否正确",{"2":{"42":2}}],["后者有则返回后者",{"2":{"554":1}}],["后者将覆盖前者的属性或方法",{"2":{"554":1}}],["后者的值将对前者的值进行扩展",{"2":{"554":1}}],["后代",{"2":{"476":1}}],["后续的重复元素位置与indexof返回的位置不相等",{"2":{"364":2}}],["后续的重复元素位置与indexof返回的位置相等",{"2":{"364":2}}],["后续所有组件都是基于根组件的",{"2":{"82":2}}],["后序遍历",{"2":{"299":3}}],["后移",{"2":{"290":2}}],["后移索引变为preindex+1",{"2":{"290":1}}],["后的最小值得索引",{"2":{"288":2}}],["后自增",{"2":{"254":2}}],["后",{"2":{"214":2}}],["后面命令覆盖",{"2":{"61":2}}],["后台守护启动",{"2":{"57":1}}],["后台守护启动docker",{"2":{"57":1}}],["后台运行",{"2":{"56":2}}],["后端改动了大量的关联关系",{"2":{"609":1}}],["后端代码",{"0":{"46":1}}],["后端接收的参数名",{"2":{"45":2}}],["后不要写额外代码",{"2":{"29":1}}],["未设置include时",{"2":{"439":1}}],["未开启strictnullchecks",{"2":{"434":2}}],["未处理的null和undefined经常会导致bug的产生",{"2":{"434":1}}],["未知类型不能直接赋值给其他变量",{"2":{"400":2}}],["未知类型",{"2":{"400":2}}],["未知的错误",{"2":{"43":2}}],["未收集",{"2":{"326":2}}],["未停止",{"2":{"56":2}}],["未传过",{"2":{"14":1}}],["失败状态",{"2":{"303":2,"304":2}}],["失败",{"2":{"239":2,"242":2,"313":2,"315":2,"610":2}}],["失败执行",{"2":{"239":2}}],["失败后产生的错误",{"2":{"43":2}}],["失败为undefined",{"2":{"16":2}}],["捕获异常",{"0":{"242":1}}],["捕获解析",{"2":{"43":2}}],["捕获项目异常错误的中间件",{"2":{"29":1}}],["并去找到npm",{"2":{"563":1}}],["并对其进行修改和优化",{"2":{"548":1}}],["并执行它们的",{"2":{"548":1}}],["并执行person函数",{"2":{"498":2}}],["并访问该节点",{"2":{"544":1}}],["并发请求函数",{"2":{"494":2}}],["并继承被",{"2":{"491":1}}],["并返回一个新的promise对象",{"2":{"529":1}}],["并返回给",{"2":{"450":1}}],["并返回数组",{"2":{"387":1}}],["并请求",{"2":{"449":1}}],["并在每个文件里加入",{"2":{"440":2}}],["并在每次迭代时在",{"2":{"392":1}}],["并在并命令行执行npm",{"2":{"421":1}}],["并在超出容量时删除最久未被使用的元素",{"2":{"296":2}}],["并转换为整数数组",{"0":{"391":1}}],["并生成树状结构",{"2":{"357":2}}],["并集",{"0":{"320":1,"322":1,"326":1},"1":{"321":1,"322":1,"323":1,"324":1,"325":1,"326":1,"327":1,"328":1}}],["并处理异步事件",{"2":{"293":2}}],["并选取中心轴的值",{"2":{"289":2}}],["并不为元素预留空间",{"2":{"479":1}}],["并不是所有函数里的代码都有返回值时",{"2":{"440":2}}],["并不安全",{"2":{"270":1}}],["并不会生成一个排好序的新数组",{"2":{"387":1}}],["并不会等待所有异步操作执行完",{"2":{"243":2}}],["并不会显示",{"2":{"121":2}}],["并将全局代码解析执行完成后",{"2":{"456":1}}],["并将他们统一存储到一个数组中返回",{"2":{"264":2}}],["并将其写入到",{"2":{"221":1}}],["并将其添加到暂存区",{"2":{"216":1}}],["并",{"2":{"234":1,"509":2}}],["并根据",{"2":{"221":1}}],["并自动生成变更日志",{"2":{"218":1}}],["并开启交互模式",{"2":{"210":2}}],["并可以指定格式",{"2":{"132":1}}],["并且要求浏览器在下次重绘之前调用指定的回调函数更新动画",{"2":{"526":1}}],["并且等待回调执行的时候进入下一次递归",{"2":{"525":2}}],["并且实现了",{"2":{"507":1}}],["并且通常比位图更小",{"2":{"486":1}}],["并且可以让开发者自己控制管理缓存的内容以及版本",{"2":{"497":1}}],["并且可以被无限放大或缩小而不会失去精度",{"2":{"484":1}}],["并且可以在不修改一个类的前提对其进行扩展",{"2":{"271":1}}],["并且不加单位",{"2":{"302":2}}],["并且将新对象设置为函数中的this",{"2":{"278":1}}],["并且会返回resolve的结果",{"2":{"240":1}}],["并且分别有",{"2":{"213":2}}],["并且总数据不能小于1",{"2":{"159":2}}],["并且位于根模块的",{"2":{"82":2}}],["并且只从一个根组件开始引导",{"2":{"82":2}}],["并把它们逐个插入到浏览器的",{"2":{"82":2}}],["并使用",{"2":{"43":2}}],["并通过浏览器解析渲染出来",{"2":{"484":1}}],["并通过该实例调用到原型上的render方法",{"2":{"140":1}}],["并通过",{"2":{"43":2}}],["的回调参数",{"2":{"615":2}}],["的示例代码",{"2":{"615":1}}],["的问题",{"2":{"588":1}}],["的组件是以",{"2":{"560":1}}],["的内部环境",{"2":{"548":1}}],["的前面",{"2":{"547":1}}],["的时间复杂度为",{"2":{"543":1,"544":1}}],["的时候",{"2":{"475":1}}],["的异同",{"0":{"533":1}}],["的实例",{"2":{"499":1}}],["的实例function",{"2":{"499":1}}],["的变化",{"2":{"466":1}}],["的变化几乎不会影响渲染主线程",{"2":{"466":1}}],["的效率高",{"2":{"466":1}}],["的本质就是重新根据分层信息计算了绘制指令",{"2":{"466":1}}],["的本质就是重新计算",{"2":{"465":1}}],["的操作",{"2":{"465":1,"560":1}}],["的工作是在预解析线程中进行的",{"2":{"456":1}}],["的响应报文也由四部分组成",{"2":{"454":1}}],["的系统调用",{"2":{"450":1}}],["的标准",{"2":{"448":1}}],["的计时器最终调用的是操作系统的函数",{"2":{"448":1}}],["的路径映射的列表",{"2":{"440":2}}],["的返回值类型",{"2":{"400":1}}],["的返回值类型字面量\\t",{"2":{"400":1}}],["的顺序",{"2":{"388":1}}],["的顺序保存原样",{"2":{"388":1}}],["的相对位置不变",{"2":{"388":1}}],["的数组",{"2":{"378":1}}],["的第一个参数",{"2":{"378":2}}],["的差集",{"2":{"324":2}}],["的元素组进行排序",{"2":{"291":2}}],["的元素编为一个组",{"2":{"291":2}}],["的元数据中指定的样式只会对该组件的模板生效",{"2":{"100":1}}],["的形式添加的属性",{"2":{"274":1}}],["的代码",{"2":{"271":1}}],["的插件",{"2":{"221":1}}],["的提交",{"2":{"210":1}}],["的提交git",{"2":{"210":1}}],["的合并简写形式",{"2":{"173":1}}],["的diff比较",{"2":{"147":2}}],["的方式去获取",{"2":{"141":1}}],["的",{"2":{"129":2,"440":2,"477":1,"554":1}}],["的优点包括",{"2":{"560":1}}],["的优点",{"2":{"125":1}}],["的有效期",{"2":{"43":2}}],["的所有元素组成",{"2":{"359":1}}],["的所有",{"2":{"4":2}}],["将相对于该先祖容器定位",{"2":{"605":1}}],["将生成的静态文件放在上级目录下",{"2":{"573":1}}],["将生成的静态文件放在当前目录下",{"2":{"573":1}}],["将生成的静态文件放在根目录下",{"2":{"573":1}}],["将后者的",{"2":{"554":1}}],["将后者的生命周期钩子函数拼接到前者的生命周期钩子函数",{"2":{"554":1}}],["将canvas的宽高设置为图像的宽高",{"2":{"551":2}}],["将文件转换为模块",{"2":{"548":1}}],["将各种类型的文件",{"2":{"548":1}}],["将该节点的所有子节点入队",{"2":{"544":1}}],["将队头节点出队",{"2":{"544":1}}],["将根节点入队",{"2":{"544":1}}],["将数字转为整数",{"2":{"513":1}}],["将this关键字指向新对象",{"2":{"498":2}}],["将一些不常更新的内容缓存在浏览器",{"2":{"497":1}}],["将一个可能是undefined或null的变量赋给一个有确切类型的变量时",{"2":{"134":1}}],["将任务并发分发到多个web",{"2":{"492":1}}],["将页面上非关键图片设置为延迟加载",{"2":{"486":1}}],["将图片缓存在用户的浏览器中",{"2":{"486":1}}],["将图片存储在专门的cdn",{"2":{"486":1}}],["将图片大小进行压缩",{"2":{"486":1}}],["将多张小图片合并到一张大图中",{"2":{"486":1}}],["将多个小图片合并为一个base64编码字符串",{"2":{"485":1}}],["将多维数组转化为一维",{"0":{"383":1}}],["将子元素都margin改为父元素的padding",{"2":{"482":1}}],["将每个快变成位图",{"2":{"463":1}}],["将每个文件做为单独的模块",{"2":{"440":2}}],["将布局渲染到屏幕上",{"2":{"455":1}}],["将事先传递的回调函数包装成任务",{"2":{"447":1}}],["将代码与",{"2":{"440":2}}],["将代码合并为一个文件",{"2":{"414":2}}],["将输出文件合并为一个文件",{"2":{"440":2}}],["将不含oss的替换",{"0":{"352":1}}],["将链接替换为想要的网址",{"0":{"351":1}}],["将模式串设置为",{"2":{"301":2}}],["将新节点添加到链表头部",{"2":{"296":2}}],["将访问的元素删除并重新添加到最前面",{"2":{"296":2}}],["将构造函数的prototype属性设置为新对象的原型",{"2":{"278":1}}],["将会发生这4件事",{"2":{"278":1}}],["将需要保护的数据设置为私有",{"2":{"270":1}}],["将时间转换为本地的字符串",{"2":{"268":2}}],["将日期转换为本地的字符串\\t\\t",{"2":{"268":2}}],["将map转换为数组",{"2":{"265":1}}],["将其设置为",{"2":{"221":1}}],["将更改提交到正确的分支上",{"2":{"217":1}}],["将错误分支上的提交移动到正确分支上",{"2":{"217":1}}],["将指定的提交复制到当前分支",{"2":{"216":1}}],["将render返回的虚拟dom转为真实dom",{"2":{"140":1}}],["将返回的虚拟dom转为真实dom",{"2":{"139":2}}],["将值转成json格式",{"2":{"132":1}}],["将ngmodeloptions",{"2":{"118":1}}],["将组件到模版",{"2":{"113":2}}],["将组件试图添加到试图树中",{"2":{"113":2}}],["将主机目录下的文件拷贝到镜像",{"2":{"61":2}}],["将宿主机的文件拷贝到镜像",{"2":{"61":2}}],["将",{"2":{"43":2,"455":1}}],["将登录成功后的用户信息",{"2":{"42":2}}],["^零+",{"2":{"302":2}}],["^$",{"2":{"302":2}}],["^",{"2":{"43":2,"157":2,"287":6,"302":2,"342":4,"345":2,"346":6,"348":2,"350":2}}],["^p",{"2":{"4":2}}],["挂载到",{"2":{"43":2}}],["字体排印",{"0":{"196":1},"1":{"197":1,"198":1,"199":1,"200":1,"201":1,"202":1,"203":1}}],["字体大小",{"2":{"116":8}}],["字符属性",{"2":{"345":2}}],["字符中",{"2":{"43":2}}],["字符串常用方法",{"0":{"530":1},"1":{"531":1,"532":1,"533":1}}],["字符串数组",{"2":{"399":2}}],["字符串数组每项长度",{"0":{"391":1}}],["字符串匹配和替换",{"2":{"338":1}}],["字符串搜索算法",{"0":{"301":1}}],["字符串形式",{"2":{"145":4}}],["字符串",{"2":{"43":4}}],["字符串解析还原成",{"2":{"43":2}}],["字段",{"2":{"4":2}}],["分包和共享依赖",{"0":{"571":1}}],["分块工作交给多个线程同时进行",{"2":{"462":1}}],["分块tiling",{"0":{"462":1}}],["分块",{"2":{"455":1}}],["分层layer",{"0":{"460":1}}],["分层",{"2":{"455":1}}],["分支后",{"2":{"396":2}}],["分支名",{"2":{"206":4,"209":2,"212":2}}],["分奇偶情况求中位数",{"2":{"292":2}}],["分隔符乱码问题",{"0":{"225":1}}],["分为公开库和私有库",{"2":{"49":1}}],["分别是",{"2":{"43":2,"422":1,"455":1}}],["分页与搜索条件记录并回显优化",{"0":{"154":1},"1":{"155":1,"156":1,"157":1,"158":1}}],["分页",{"2":{"4":1}}],["签名",{"2":{"43":1}}],["服务开启",{"0":{"613":1}}],["服务端通多用户信息生成",{"2":{"43":1}}],["服务器打包预览环境变量",{"2":{"573":2}}],["服务器端等",{"2":{"560":1}}],["服务器端响应",{"0":{"454":1}}],["服务器与浏览器之间的中间人",{"2":{"496":1}}],["服务器与普通电脑",{"2":{"19":1}}],["服务器上",{"2":{"486":1}}],["服务器上安装了",{"2":{"19":1}}],["服务器会返回http状态码304",{"2":{"471":1}}],["服务器",{"2":{"450":1,"497":1}}],["服务器必须得提供并返回该域名的",{"2":{"450":1}}],["服务器发起域名解析请求",{"2":{"450":1}}],["服务器响应",{"2":{"449":1}}],["服务器通过还原",{"2":{"43":1}}],["服务器挨个处理访问队列里的访问",{"2":{"40":1}}],["服务器不会保留每次",{"2":{"40":1}}],["服务器运行在localhost",{"2":{"22":4}}],["服务器运行在",{"2":{"20":2}}],["服务器监听到请求",{"2":{"20":2}}],["服务器实例",{"2":{"20":1}}],["服务器步骤",{"0":{"20":1}}],["服务器软件",{"2":{"19":1}}],["服务器操作",{"0":{"19":1},"1":{"20":1,"21":1,"22":1}}],["需要重新设置对齐线",{"2":{"611":2}}],["需要重新计算布局树",{"2":{"465":1}}],["需要手动从flexsearch中引入",{"2":{"602":1}}],["需要手动执行",{"2":{"205":1}}],["需要在",{"2":{"590":1,"602":1}}],["需要在边框内留白",{"2":{"482":1}}],["需要在边框外留白",{"2":{"482":1}}],["需要调节定时器时间使比较不突兀",{"2":{"584":2}}],["需要编写相应的判断程序",{"2":{"496":1}}],["需要自己编写代码来实现各种绘图功能",{"2":{"484":1}}],["需要更新属性",{"2":{"466":1}}],["需要包含的类型声明文件名列表",{"2":{"440":2}}],["需要设置lib选项",{"2":{"431":1}}],["需要隐含当any需要明确指出",{"2":{"428":2}}],["需要同时启用",{"2":{"427":1}}],["需要进行编译才能转换为javascript代码",{"2":{"425":1}}],["需要添加一些额外的检查",{"2":{"316":1}}],["需要一个对象作为参数",{"2":{"268":2}}],["需要",{"0":{"219":1}}],["需要执行此命令进行变基",{"2":{"213":1}}],["需要执行此命令进行变基git",{"2":{"213":1}}],["需要再次提交",{"0":{"213":1}}],["需要拉取合并原仓库的更新",{"2":{"211":1}}],["需要多次推送",{"2":{"211":1}}],["需要给相邻元素添加",{"2":{"180":2}}],["需要通过绑定",{"2":{"141":1}}],["需要做额外配置",{"2":{"42":1}}],["需要配合",{"2":{"42":1}}],["方便同时更新",{"2":{"211":1}}],["方案",{"2":{"584":1}}],["方案四",{"2":{"551":1}}],["方案三",{"2":{"551":1}}],["方案二",{"0":{"250":1},"2":{"159":2,"279":2,"551":1,"574":2,"585":2}}],["方案一",{"0":{"249":1},"2":{"159":3,"279":2,"551":1,"574":2,"583":1,"585":2}}],["方法中谁调用就指向谁",{"2":{"517":1}}],["方法名",{"2":{"404":2}}],["方法调用回调函数",{"2":{"392":1}}],["方法用原地算法对数组的元素进行排序",{"2":{"387":1}}],["方法被调用的数组",{"2":{"368":2}}],["方法三",{"2":{"287":2}}],["方法等",{"2":{"274":1}}],["方法二",{"0":{"217":1,"494":1},"1":{"219":1},"2":{"116":1,"211":1,"287":2,"302":1,"322":2,"324":2,"327":2,"520":2,"539":2}}],["方法一",{"0":{"216":1,"493":1},"2":{"116":1,"211":1,"287":2,"302":1,"322":2,"327":2,"520":2,"539":2}}],["方法生成",{"2":{"43":2}}],["方法",{"2":{"42":2,"112":1,"266":2,"275":1,"283":2,"408":2,"507":1,"533":1,"548":1}}],["方式三",{"0":{"504":1}}],["方式添加的方法",{"2":{"274":1}}],["方式二",{"0":{"239":1,"503":1},"2":{"36":2,"37":2,"527":2}}],["方式一",{"0":{"238":1,"502":1},"2":{"36":2,"37":2,"527":2}}],["信息安全",{"2":{"469":1}}],["信息不安全",{"2":{"469":1}}],["信息",{"2":{"42":2}}],["响应式系统不需要深度遍历就可以对整个对象监听",{"2":{"561":1}}],["响应体",{"2":{"454":1}}],["响应头",{"2":{"454":1}}],["响应行",{"2":{"454":1}}],["响应给客户端",{"2":{"42":2}}],["响应文件内容",{"0":{"22":1}}],["从入口文件抽离",{"2":{"571":2}}],["从目标元素向外传播",{"2":{"528":1}}],["从根元素",{"2":{"528":1}}],["从左往右",{"2":{"509":2}}],["从本地缓存里面读取文件",{"2":{"471":1}}],["从一个切换到另一个",{"2":{"443":1}}],["从另一个配置文件里继承配置",{"2":{"440":2}}],["从而减少了不必要的",{"2":{"560":1}}],["从而实现多个异步操作的顺序执行和数据传递",{"2":{"529":1}}],["从而实现快速匹配",{"2":{"301":2}}],["从而形成一个promise链",{"2":{"529":1}}],["从而保持正方形",{"2":{"490":1}}],["从而加快加载速度",{"2":{"486":1}}],["从而最大限度的保证了单线程的流畅运行",{"2":{"447":1}}],["从而导致消息队列中的很多其他任务无法得到执行",{"2":{"447":1}}],["从而导致编译报错",{"2":{"425":1}}],["从而更愉快的从js转为ts开发",{"2":{"425":1}}],["从索引0开始",{"2":{"378":1}}],["从索引0开始arr",{"2":{"378":1}}],["从索引1的地方开始执行callback方法",{"2":{"378":2}}],["从后往前分割",{"2":{"302":2}}],["从后端服务器拿到数据",{"2":{"111":1}}],["从小到大",{"2":{"290":2}}],["从大到小",{"2":{"290":2}}],["从stash中取出暂存的代码修改",{"2":{"212":1}}],["从stash中取出暂存的代码修改git",{"2":{"212":1}}],["从这本书字里行间可以感受到作者也是个有趣的灵魂",{"2":{"181":1}}],["从query中获取分页信息",{"2":{"157":2}}],["从v11开始",{"2":{"113":1}}],["从容停止",{"2":{"72":1}}],["从tar包中恢复成镜像",{"2":{"59":2}}],["从搬家到搬楼",{"2":{"47":1}}],["从",{"2":{"42":2,"440":2}}],["从下一切片开始传",{"2":{"14":1}}],["中国标准时间",{"2":{"533":2}}],["中如果结束索大于起始索引",{"2":{"532":1}}],["中可以做拦截客户端的请求",{"2":{"496":1}}],["中的一个节点",{"2":{"560":1}}],["中的",{"2":{"506":1}}],["中的外部",{"2":{"456":1}}],["中的计时器能做到精确计时吗",{"2":{"448":1}}],["中所有的配置信息都应该写在module",{"2":{"418":2}}],["中序遍历",{"2":{"299":3}}],["中文版",{"2":{"588":1}}],["中文香港",{"2":{"268":2}}],["中文中国",{"2":{"268":2}}],["中受控组件的是指表单元素的控制是交给",{"2":{"141":1}}],["中每个条目的值",{"2":{"122":2}}],["中获取用户的名称",{"2":{"42":2}}],["中",{"0":{"491":1},"2":{"42":2,"82":2,"129":4,"392":1,"483":1,"543":2,"544":2,"573":3}}],["中间件分类",{"2":{"29":1}}],["中间件函数必须有next",{"2":{"29":1}}],["中间件注意事项",{"2":{"29":1}}],["中间件mw2被执行了",{"2":{"29":2}}],["中间件mw1被执行了",{"2":{"29":4}}],["中间件本质",{"2":{"29":1}}],["中间件",{"0":{"29":1},"2":{"42":2}}],["中间的",{"2":{"15":2}}],["中间的区块",{"2":{"15":2}}],["登录接口",{"2":{"43":2}}],["登录成功",{"2":{"42":2,"43":4}}],["登录失败",{"2":{"42":2,"43":4}}],["登录的",{"2":{"42":2}}],["提取公共代码等",{"2":{"548":1}}],["提高了性能",{"2":{"560":1}}],["提高访问体验",{"2":{"497":1}}],["提高用户体验",{"0":{"486":1},"2":{"486":1}}],["提高页面的加载速度和响应性",{"2":{"486":1}}],["提高页面性能",{"2":{"485":1}}],["提高页面加载速度",{"2":{"485":1,"486":2}}],["提出了java等服务器端语言早就有的装饰器模式",{"2":{"426":1}}],["提交代码时",{"2":{"221":1}}],["提交代码并生成变更日志",{"2":{"221":1}}],["提交规范和",{"2":{"218":1}}],["提交规范化",{"0":{"218":1},"1":{"219":1,"220":1,"221":1}}],["提交信息校验脚手架",{"2":{"218":1}}],["提交过程的不同阶段自动运行脚本",{"2":{"218":1}}],["提交过来的表单数据",{"2":{"42":2}}],["提交完未推送前",{"0":{"213":1},"2":{"213":1}}],["提升运算速率",{"2":{"463":1}}],["提升效率",{"2":{"345":2}}],["提升项目性能",{"2":{"149":1}}],["提升性能",{"2":{"122":2}}],["提供",{"2":{"456":1}}],["提供setter和getter方法来开放对数据的操作",{"2":{"270":1}}],["提供别名",{"2":{"95":2}}],["提供各种服务",{"2":{"78":1}}],["提示",{"2":{"14":1}}],["提示已弃用",{"2":{"5":2}}],["解法三",{"2":{"283":2,"512":2}}],["解法二",{"2":{"283":2,"512":2}}],["解法一",{"2":{"283":2,"512":2}}],["解释",{"2":{"167":1,"168":1,"527":1}}],["解析到错误",{"2":{"590":1}}],["解析成对象",{"2":{"456":1}}],["解析的根本原因",{"2":{"456":2}}],["解析过程中遇到",{"2":{"456":1}}],["解析器负责识别处理的语法元素",{"2":{"129":2}}],["解析失败导致的",{"2":{"43":2}}],["解析",{"0":{"425":1,"456":1,"457":1},"1":{"426":1,"427":1,"428":1,"429":1,"430":1,"431":1,"432":1,"433":1,"434":1,"435":1,"436":1,"437":1,"438":1,"439":1,"440":1},"2":{"42":2,"43":2,"279":1,"338":1,"445":2,"455":3,"456":1}}],["解决构造函数浪费内存问题",{"2":{"499":1}}],["解决链式调用",{"2":{"315":2}}],["解决异常",{"2":{"308":4,"310":2}}],["解决后输出",{"2":{"307":1}}],["解决前输出",{"2":{"307":1}}],["解决同步代码需要等待执行问题",{"0":{"307":1}}],["解决方案",{"2":{"279":1,"610":2}}],["解决方法",{"2":{"243":1,"349":2,"586":1,"605":1}}],["解决冲突",{"2":{"217":1}}],["解决痛点",{"0":{"47":1}}],["解决中文乱码两种方法",{"2":{"20":2}}],["解决文件路径动态拼接问题",{"2":{"16":1}}],["解决",{"0":{"594":1},"2":{"16":1,"526":1}}],["托管静态页面",{"2":{"42":2}}],["认证弊端",{"2":{"42":1}}],["认证",{"0":{"42":1,"43":1},"2":{"42":1}}],["注",{"2":{"450":1}}],["注2",{"2":{"405":1}}],["注1",{"2":{"405":1}}],["注册svg",{"2":{"578":2}}],["注册iconfont",{"2":{"578":2}}],["注册iconfont节点",{"2":{"578":4}}],["注册虚线动画",{"2":{"578":2}}],["注册实线动画",{"2":{"578":2}}],["注册节点添加label图形时动态计算label位置",{"2":{"580":2}}],["注册节点",{"0":{"578":1}}],["注册将",{"2":{"43":2}}],["注册成功",{"2":{"9":2}}],["注意仓库名和路径名不一致问题",{"2":{"396":2}}],["注意在",{"2":{"396":2}}],["注意在此项目的",{"2":{"396":2}}],["注意替换为你的",{"2":{"396":8}}],["注意点",{"2":{"308":1}}],["注意大小写",{"2":{"146":1}}],["注意与其他组件发生样式冲突",{"2":{"101":1}}],["注意",{"0":{"219":1},"2":{"41":1,"43":2,"85":2,"111":1,"137":1,"145":1,"147":2,"235":1,"433":2,"434":1}}],["自带",{"2":{"555":2}}],["自适应方案",{"2":{"488":1}}],["自身立即结束任务的执行",{"2":{"447":1}}],["自身",{"2":{"277":2}}],["自增和自减",{"0":{"254":1}}],["自己解决自己的",{"2":{"594":1}}],["自己的pwsh",{"2":{"231":2}}],["自己的安装目录",{"2":{"224":2,"227":2}}],["自己用户名",{"2":{"222":1}}],["自动生成侧边栏sidebar",{"2":{"599":2}}],["自动生成html",{"2":{"418":2}}],["自动响应浏览器更新",{"2":{"418":2}}],["自动部署",{"0":{"394":1},"1":{"395":1,"396":1}}],["自动",{"2":{"197":2}}],["自动填充",{"2":{"165":1}}],["自动打开浏览器等",{"2":{"149":1}}],["自动刷新",{"2":{"149":1}}],["自动订阅模板中的observable或promise",{"2":{"132":1}}],["自动发送",{"2":{"41":1}}],["自定义样式覆盖就好啦",{"2":{"605":1}}],["自定义目录不能根据视口固定",{"0":{"605":1}}],["自定义的类名快捷键不能写在变体后面",{"2":{"586":1}}],["自定义的模块",{"2":{"80":2}}],["自定义节点和节点动画",{"2":{"578":2}}],["自定义高阶函数",{"0":{"390":1},"1":{"391":1,"392":1,"393":1}}],["自定义高亮指令",{"0":{"125":1}}],["自定义对象",{"2":{"278":1}}],["自定义主题",{"0":{"229":1}}],["自定义下划线",{"0":{"199":1}}],["自定义滚动条",{"0":{"177":1},"2":{"177":2}}],["自定义方法",{"2":{"143":2}}],["自定义组件",{"2":{"141":1}}],["自定义unless指令",{"0":{"126":1}}],["自定义指令",{"0":{"124":1},"1":{"125":1,"126":1}}],["自定义管道",{"0":{"107":1}}],["自定义属性选择器投影内容",{"2":{"102":2}}],["自定义属性绑定",{"0":{"87":1}}],["自定义网络",{"0":{"64":1}}],["自定义模块",{"2":{"23":1,"26":1}}],["无疑也是一个不错的思路和方法",{"2":{"594":1}}],["无复制内容",{"2":{"574":2}}],["无状态的",{"2":{"452":1}}],["无状态性",{"2":{"40":1}}],["无法做到精确计时",{"2":{"448":1}}],["无法转换",{"2":{"302":2}}],["无法修改",{"2":{"262":1}}],["无需创建实例即可完成对类的修改",{"2":{"275":1}}],["无需真实dom上那么多的属性",{"2":{"137":1}}],["无论放大或缩小都保持清晰度",{"2":{"484":1}}],["无论属性在对象自身还是在原型中",{"2":{"277":1}}],["无论用户是否定义形参",{"2":{"263":2}}],["无论成功失败",{"2":{"239":2}}],["无",{"2":{"197":2}}],["无效的token",{"2":{"43":2}}],["无连接",{"2":{"40":1}}],["九",{"0":{"39":1,"62":1,"311":1,"464":1},"1":{"40":1,"41":1,"42":1,"43":1,"63":1,"64":1},"2":{"302":6}}],["硬删除成功",{"2":{"38":2}}],["硬删除",{"2":{"38":1}}],["返回operate传的实参",{"2":{"540":2}}],["返回不同进制的字符串形式的数值",{"2":{"533":1}}],["返回空",{"2":{"532":1}}],["返回指定索引位的",{"2":{"531":2}}],["返回新创建的对象",{"2":{"498":1}}],["返回的结果是按升序来排列的",{"2":{"388":2}}],["返回数组元素平方后的新数组",{"0":{"370":1}}],["返回数据给客户端",{"2":{"20":2}}],["返回加工后新数组",{"2":{"367":1}}],["返回奇数元素",{"0":{"363":1}}],["返回值",{"2":{"388":3,"533":1}}],["返回值组成的新数组",{"2":{"367":1}}],["返回值是一个新数组",{"2":{"359":1}}],["返回值的判断与处理",{"0":{"309":1}}],["返回a与b数组区别的集合",{"2":{"324":2}}],["返回所有类型的键名",{"2":{"318":2}}],["返回对象自身的所有可枚举的属性的键名",{"2":{"318":2}}],["返回类型约束",{"0":{"311":1}}],["返回给定起止字符串月份中间所有月份",{"0":{"294":1}}],["返回",{"2":{"279":1,"296":10,"507":1,"531":2}}],["返回一个新函数",{"2":{"262":2}}],["返回自增后的值",{"2":{"254":2}}],["返回自增前的值",{"2":{"254":2}}],["返回结果",{"2":{"36":2}}],["否则返回前者",{"2":{"554":1}}],["否则返回false",{"2":{"255":4,"256":2}}],["否则为",{"2":{"430":1}}],["否则为错误对象",{"2":{"16":2}}],["否则不匹配返回",{"2":{"279":1}}],["否则不匹配",{"2":{"279":1}}],["否则不变",{"2":{"159":2}}],["否则比较其他case后的表达式",{"2":{"259":2}}],["否则报错如下",{"0":{"219":1}}],["否则报错er",{"2":{"36":2}}],["否则取计算得到的页",{"2":{"159":2}}],["占位符的数量和表的列数需要一致",{"2":{"36":2}}],["qqssh",{"2":{"234":1}}],["qq",{"2":{"232":2,"234":1}}],["qobj",{"2":{"158":4}}],["q",{"2":{"56":4}}],["q只显示id",{"2":{"55":2}}],["qstr",{"2":{"35":4}}],["queue",{"2":{"493":8,"544":14}}],["querychartdata",{"2":{"577":4}}],["queryselectorall",{"2":{"249":2,"250":2,"536":2}}],["queryaccount",{"2":{"159":2}}],["queryxxx",{"2":{"158":6}}],["queryfn",{"2":{"157":2}}],["querylist中监听子组件变化的回调函数",{"2":{"104":2}}],["querylist",{"2":{"104":6,"106":6}}],["query",{"2":{"7":2,"30":4,"34":2,"35":2,"36":4,"37":4,"38":4,"157":20,"158":2}}],["quicksort",{"2":{"289":6}}],["quit",{"2":{"72":1}}],["quot",{"2":{"4":30,"6":4,"15":32,"20":8,"21":24,"22":88,"37":16,"38":16,"45":8,"46":88,"55":8,"56":8,"61":24,"73":4,"86":28,"87":8,"88":8,"89":72,"90":48,"91":20,"92":24,"93":8,"95":8,"96":8,"102":16,"104":12,"105":12,"106":4,"107":8,"108":20,"109":2,"113":20,"114":40,"116":44,"117":32,"118":32,"121":32,"122":44,"123":136,"126":16,"130":20,"134":4,"137":8,"139":32,"144":16,"145":28,"146":16,"150":8,"151":4,"152":4,"153":4,"157":4,"158":100,"159":8,"168":28,"170":28,"178":64,"211":20,"213":4,"220":12,"221":8,"224":4,"227":4,"231":68,"238":20,"243":16,"262":8,"265":28,"268":28,"269":8,"271":12,"272":4,"276":4,"283":8,"288":4,"295":8,"298":12,"301":16,"302":316,"303":4,"308":28,"310":8,"311":12,"313":8,"314":8,"315":12,"316":12,"318":8,"335":12,"340":4,"341":16,"342":8,"346":20,"347":4,"349":12,"350":8,"357":80,"364":20,"372":4,"396":4,"400":4,"412":8,"414":132,"418":60,"419":24,"420":32,"423":48,"424":72,"426":8,"429":16,"430":16,"432":8,"433":28,"438":4,"439":24,"440":244,"471":2,"478":64,"482":16,"490":4,"491":4,"493":16,"494":28,"523":4,"532":8,"551":36,"571":36,"573":36,"574":40,"577":104,"578":268,"580":16,"584":32,"585":48,"586":20,"587":24,"592":2,"602":20,"609":24,"610":120,"612":4,"613":4,"614":20}}],["测试环境能访问sitemap",{"2":{"590":1}}],["测试代码",{"2":{"494":2}}],["测试数据",{"2":{"319":1}}],["测试示例",{"2":{"318":1}}],["测试连接是否成功",{"2":{"235":1}}],["测试等操作",{"2":{"218":1}}],["测试unless",{"2":{"126":4}}],["测试自定义标题属性",{"2":{"87":2}}],["测试sudo",{"2":{"51":1}}],["测试",{"2":{"34":2,"51":1,"285":2,"293":1,"298":2,"299":3,"313":1,"314":1,"493":2}}],["八",{"0":{"33":1,"61":1,"310":1,"463":1},"1":{"34":1,"35":1,"36":1,"37":1,"38":1},"2":{"302":6}}],["头部投影内容",{"2":{"102":2}}],["头部",{"0":{"32":1},"2":{"43":1}}],["七",{"0":{"30":1,"53":1,"309":1,"462":1},"1":{"31":1,"32":1,"54":1,"55":1,"56":1,"57":1,"58":1,"59":1,"60":1},"2":{"302":6}}],["错误",{"2":{"440":2}}],["错误级别中间件",{"2":{"29":1}}],["错误为null",{"2":{"18":2}}],["路由组件切换",{"0":{"612":1}}],["路由器的默认行为是从根路径",{"2":{"572":1}}],["路由级别中间件",{"2":{"29":1}}],["路径",{"2":{"414":2}}],["路径模块",{"0":{"17":1}}],["应用",{"0":{"537":1},"2":{"520":1}}],["应用层的协议",{"2":{"452":1}}],["应用是通过引导根模块",{"2":{"82":1}}],["应用级别中间件",{"2":{"29":1}}],["应用场景",{"0":{"338":1},"2":{"0":1}}],["和主机名的传送",{"2":{"590":1}}],["和其他类型平等关系",{"2":{"400":2}}],["和数组相似",{"2":{"263":2}}],["和",{"0":{"560":1},"2":{"29":1,"43":2,"150":1,"174":1,"211":3,"213":2,"240":1,"262":2,"318":2,"322":4,"388":1,"439":1,"455":1,"471":1,"479":1,"495":1,"509":2,"533":2}}],["连接",{"2":{"451":1}}],["连接的建立",{"2":{"451":1}}],["连接数据库并测试",{"2":{"34":1}}],["连接数据库",{"0":{"33":1},"1":{"34":1,"35":1,"36":1,"37":1,"38":1}}],["连接数据库后默认在test库",{"2":{"1":2}}],["连续调用的多个中间件共享",{"2":{"29":1}}],["函数柯里化",{"0":{"539":1},"1":{"540":1,"541":1},"2":{"537":1}}],["函数柯里化传参",{"2":{"146":2}}],["函数体内部使用yield表达式",{"2":{"524":1}}],["函数声明会覆盖其他的同名的变量声明",{"2":{"514":1}}],["函数封装",{"0":{"494":1}}],["函数用于执行不到返回值那一步",{"2":{"400":2}}],["函数时使用的this",{"2":{"368":2}}],["函数的回调中获取本次程序结果",{"2":{"525":2}}],["函数的隐式原型对象",{"0":{"500":1}}],["函数的实参直接在第一个参数后一个一个的列出来",{"2":{"262":1}}],["函数的柯里化",{"2":{"146":1}}],["函数三种调用方式",{"2":{"262":1}}],["函数组件使用props",{"2":{"144":1}}],["函数式组件",{"0":{"139":1},"2":{"139":2}}],["函数",{"2":{"29":1,"378":3,"539":2}}],["函数可以流转关系转交给下一个中间件或路由",{"2":{"29":1}}],["多了的话就显得很麻烦不够优雅",{"2":{"596":1}}],["多次进入详情页",{"2":{"559":2}}],["多边形和文本等基本几何形状来创建",{"2":{"484":1}}],["多维数组",{"2":{"282":2}}],["多态",{"0":{"272":1},"2":{"269":1}}],["多分支优化",{"0":{"244":1},"1":{"245":1,"246":1,"247":1}}],["多重边框",{"0":{"183":1}}],["多个请求并发发出",{"2":{"492":1}}],["多个请求之间相互独立",{"2":{"40":1}}],["多个可进行累加",{"2":{"476":1}}],["多个可选",{"2":{"399":2}}],["多个进程间不能共享资源",{"2":{"443":1}}],["多个比较用",{"2":{"256":2}}],["多个命令时只会生效最后一个",{"2":{"61":2}}],["多个局部中间件",{"2":{"29":1}}],["多条文档",{"2":{"5":1}}],["在组件卸载前",{"2":{"615":2}}],["在组件内容初始化之后调用",{"2":{"109":2}}],["在每次绑定事件前",{"2":{"612":2}}],["在main",{"2":{"609":2}}],["在博客根目录新建scripts目录并创建文件getsidebar",{"0":{"599":1}}],["在package",{"0":{"598":1}}],["在powershell配置项中添加一个配置",{"2":{"231":1}}],["在router对象中",{"2":{"572":1}}],["在render之前调用",{"2":{"147":1}}],["在diff算法中增加了静态标记",{"2":{"561":1}}],["在declarations中的组件默认只能在当前模块中使用",{"2":{"79":2}}],["在activated钩子中",{"2":{"559":2}}],["在序列中排在",{"2":{"547":1}}],["在同一浏览器的相同域名",{"2":{"522":1}}],["在设定的时间内再次触发",{"2":{"518":1}}],["在设置中配置配置自己安装的nerd",{"2":{"230":1}}],["在词法解析阶段就已经明确了未来上下文中必定会有相关变量声明",{"2":{"516":1}}],["在计算机底层都是按照",{"2":{"507":1}}],["在构造函数内部",{"2":{"498":1}}],["在构造函数中",{"2":{"269":2}}],["在web",{"2":{"497":1}}],["在现有样式加上加上新类名",{"2":{"491":4}}],["在编写项目时",{"2":{"487":2}}],["在编译过程中把这些标准库引入",{"2":{"431":1}}],["在服务器代码上设置",{"2":{"471":1}}],["在一次事件循环中",{"2":{"448":1}}],["在消息队列中先进先出",{"2":{"448":1}}],["在这一过程中",{"2":{"458":1}}],["在这种异步模式下",{"2":{"447":1}}],["在这个例子中",{"2":{"301":1}}],["在这个函数中",{"2":{"301":1}}],["在添加新任务时",{"2":{"446":1}}],["在最开始的时候",{"2":{"446":1}}],["在表达式和声明上有隐含的",{"2":{"440":2}}],["在源文件",{"2":{"432":2}}],["在src下创建ts文件",{"2":{"421":1}}],["在es6中的模块化会自动使用严格模式",{"2":{"414":2}}],["在汪汪叫",{"2":{"409":2,"410":2}}],["在没有参数时",{"2":{"388":2}}],["在对象转数字过程中",{"2":{"539":2}}],["在对象中会有一个属性用来存储原型对象",{"2":{"274":1}}],["在对象中可以通过对象的属性来对日期的格式进行配置",{"2":{"268":2}}],["在对文本串和模式串进行匹配时",{"2":{"301":2}}],["在有序数组中找位置",{"2":{"290":1}}],["在原型添加方法",{"2":{"276":2}}],["在类中通过xxx",{"2":{"274":1}}],["在类中通过",{"2":{"274":1}}],["在js中不会检查参数的类型",{"2":{"272":1}}],["在子类中",{"2":{"271":2}}],["在定义函数时可以将参数指定为剩余参数",{"2":{"264":2}}],["在进行运算",{"2":{"251":1}}],["在进行拼接",{"2":{"251":1}}],["在github",{"2":{"233":1}}],["在代码托管平台设置添加公钥",{"0":{"233":1}}],["在环境变量新增oh",{"2":{"230":1}}],["在terminal",{"2":{"225":1}}],["在ts中只能有一个构造器方法",{"2":{"405":1}}],["在ts中",{"2":{"134":1}}],["在错误分支git",{"2":{"217":1}}],["在线生成器",{"2":{"161":1}}],["在线",{"2":{"158":2}}],["在更新显示时key起着极其重要的作用",{"2":{"147":2}}],["在特定情况下",{"2":{"134":1}}],["在外部获取组件引用",{"2":{"130":1}}],["在渲染视图之前",{"2":{"128":2}}],["在相应的module中导入并使用",{"2":{"107":1}}],["在变更检测后执行",{"2":{"103":2}}],["在",{"2":{"100":1,"218":1,"234":1,"322":2,"388":1,"396":2,"483":1,"495":1,"543":1,"544":1,"548":1,"573":2,"615":1}}],["在其他模块使用必须exports导出",{"2":{"79":1}}],["在其他模块使用必须exports导出1",{"2":{"79":1}}],["在登录成功之后",{"2":{"43":2}}],["在路由中间件前使用",{"2":{"30":2}}],["在路由加一个参数",{"2":{"29":2}}],["在自定义模块中",{"2":{"24":1}}],["zinc",{"2":{"614":6}}],["zindex",{"2":{"578":10}}],["za",{"2":{"578":2}}],["zoom",{"2":{"577":2}}],["zoomin",{"2":{"577":6}}],["zoomout",{"2":{"577":6}}],["zorrosrc",{"2":{"86":6}}],["zorro",{"2":{"86":8}}],["zerdocs",{"2":{"395":2,"396":10,"599":2}}],["zshgit",{"2":{"206":1,"207":1,"208":1,"209":1,"210":2,"212":1,"213":1,"214":1,"216":1}}],["zsh",{"2":{"205":1,"211":4,"220":1,"221":2,"590":1}}],["z",{"2":{"189":4,"190":4,"345":2,"346":2,"348":4,"350":6,"479":1,"551":2,"578":4}}],["zl",{"2":{"36":10}}],["zjj被访问哈哈哈",{"2":{"29":2}}],["zjj被访问",{"2":{"29":2}}],["zjj",{"2":{"29":2}}],["zh",{"2":{"268":6}}],["zhan",{"2":{"527":2}}],["zhansan",{"2":{"262":2,"399":2}}],["zhangsna",{"2":{"399":4}}],["zhangsan",{"2":{"25":4,"29":6,"30":2,"270":2,"399":2,"536":2}}],["zhang",{"2":{"5":2}}],["zhang4",{"2":{"5":2}}],["zhang3",{"2":{"4":2,"5":2,"6":2}}],["zhaoliu",{"2":{"36":2}}],["zhj被访问哈哈哈",{"2":{"28":2,"29":2}}],["zhj被访问",{"2":{"28":2,"29":2}}],["zhj",{"2":{"28":2,"29":2}}],["可维护性和可扩展性等问题而产生的",{"2":{"549":1}}],["可解决函数嵌套导致的可读性差问题",{"2":{"540":1}}],["可能出现无限循环",{"2":{"513":1}}],["可能会导致本地分支列表过长",{"2":{"205":1}}],["可用==的情况",{"2":{"512":1}}],["可执行对象",{"2":{"506":1}}],["可定时发出多个需要并发请求",{"2":{"492":1}}],["可单个持久链接上进行多次请求",{"2":{"492":1}}],["可减少服务器负载",{"2":{"485":1}}],["可替换元素",{"0":{"483":1}}],["可查看",{"2":{"457":1}}],["可操作的能力",{"2":{"456":1}}],["可选的值有很多",{"2":{"431":1}}],["可选属性",{"2":{"412":2}}],["可选",{"2":{"360":4,"399":2}}],["可视化工具",{"0":{"339":1}}],["可控制扁平化深度",{"2":{"282":2}}],["可变参数",{"0":{"263":1}}],["可运用于隐式转布尔值",{"2":{"255":2}}],["可借鉴的up主题文件",{"2":{"229":1}}],["可改",{"2":{"220":2}}],["可迭代对象的长度",{"2":{"122":2}}],["可迭代对象中当前条目的索引",{"2":{"122":2}}],["可拆解为",{"2":{"117":1}}],["可最早获取到输入属性最新值",{"2":{"109":2}}],["可如果数组中的元素变化",{"2":{"108":1}}],["可以这样用",{"2":{"587":1}}],["可以方便地实现组件的开发",{"2":{"560":1}}],["可以轻松地支持多种平台",{"2":{"560":1}}],["可以抽离封装vue",{"2":{"554":1}}],["可以把父组件请求卸载mounted中",{"2":{"558":1}}],["可以把数据绑定到页面",{"2":{"553":1}}],["可以把ts转为es5或更早的js代码",{"2":{"429":1}}],["可以访问",{"2":{"548":1}}],["可以访问cache和indexdb",{"2":{"497":1}}],["可以处理的模块",{"2":{"548":1}}],["可以找到图的强联通分量",{"2":{"547":1}}],["可以找到图的拓扑排序",{"2":{"547":1}}],["可以找到由相邻节点组成的连通块",{"2":{"546":1,"547":1}}],["可以",{"2":{"533":1}}],["可以避免回调地狱",{"2":{"529":1}}],["可以共享",{"2":{"522":1}}],["可以创建一个独立线程",{"2":{"495":1}}],["可以使得图片加载更快",{"2":{"486":1}}],["可以使用队列来实现",{"2":{"544":1}}],["可以使用递归或栈来实现",{"2":{"543":1}}],["可以使用矢量图形代替位图",{"2":{"486":1}}],["可以使用",{"2":{"213":1,"615":1}}],["可以减少请求次数",{"2":{"486":1}}],["可以减少重复加载同一张图片的次数",{"2":{"486":1}}],["可以减少初始加载时的负担",{"2":{"486":1}}],["可以减少图片文件的大小",{"2":{"486":1}}],["可以减少浏览器与服务器之间的http请求次数",{"2":{"485":1}}],["可以制作出非常复杂的动态效果",{"2":{"484":1}}],["可以随时向消息队列添加任务",{"2":{"446":1}}],["可以随便填",{"2":{"232":2}}],["可以指定",{"2":{"438":1}}],["可以关闭该选项",{"2":{"434":1}}],["可以推导为",{"2":{"424":8}}],["可以将比较耗费资源操作放在里面执行",{"2":{"495":1}}],["可以将这些文件识别为模块",{"2":{"418":2}}],["可以将其设置为private",{"2":{"407":1}}],["可以将该类实例中",{"2":{"275":1}}],["可以修改",{"2":{"406":4}}],["可以赋值给其他类型",{"2":{"399":1}}],["可以赋值给其他类型boolean",{"2":{"399":1}}],["可以添加事件侦听器",{"2":{"293":2}}],["可以被所有该类实例访问",{"2":{"275":1}}],["可以在内存中进行操作",{"2":{"560":1}}],["可以在构建过程中执行一系列的任务",{"2":{"548":1}}],["可以在构造函数中",{"2":{"269":2}}],["可以在类中修改",{"2":{"406":3}}],["可以在类",{"2":{"406":2}}],["可以在方法中对属性的值进行验证",{"2":{"270":1}}],["可以控制属性的读写权限",{"2":{"270":1}}],["可以通过this关键字来添加属性和方法到新对象中",{"2":{"498":1}}],["可以通过",{"2":{"495":1,"497":1}}],["可以通过box",{"2":{"475":1}}],["可以通过对象修改",{"2":{"406":1}}],["可以通过对象修改class",{"2":{"406":1}}],["可以通过创建同名方法来重写父类的方法",{"2":{"271":2}}],["可以通过extends关键来完成继承",{"2":{"271":1}}],["可以通过该对象直接访问实参",{"2":{"263":2}}],["可以通过索引来读取元素",{"2":{"263":2}}],["可以不受参数数量的限制更加灵活的创建函数",{"2":{"263":2}}],["可以求任意个数值的和",{"2":{"263":2}}],["可以用来创建一个新的函数",{"2":{"262":1}}],["可以用promise",{"2":{"239":1}}],["可以用$any",{"2":{"135":1}}],["可以看到自己账户名",{"2":{"235":1}}],["可以先去microsofe",{"2":{"222":1}}],["可以结合选择器",{"2":{"197":1}}],["可以放在任何一个需要值的地方",{"2":{"137":1}}],["可以获取dom",{"2":{"130":1}}],["可以视为动态组件",{"2":{"113":1}}],["可以构建时候临时修改变量",{"2":{"61":2}}],["可以借助接口调试工具测试或直接访问",{"2":{"46":1}}],["可以配置当前",{"2":{"43":2}}],["可以伪造",{"2":{"41":1}}],["可以连续调用多个中间件对请求进行处理",{"2":{"29":1}}],["可以调用多个中间件对请求进行",{"2":{"29":1}}],["可扩展分片集群",{"2":{"0":1}}],["概念",{"2":{"29":1}}],["网站等方面的应用非常广泛",{"2":{"484":1}}],["网站服务器",{"2":{"27":1}}],["网络拓扑总览特有节点注册",{"2":{"578":2}}],["网络拓扑图代码",{"0":{"576":1},"1":{"577":1,"578":1}}],["网络",{"2":{"447":1,"449":1}}],["网络进程内部会启动多个线程来处理不同的网络任务",{"2":{"444":1}}],["网络进程",{"2":{"444":1}}],["网络名",{"2":{"62":6}}],["网格内项目垂直居中",{"2":{"474":2}}],["网格内项目对其方式",{"0":{"168":1}}],["网格相对于容器的对齐方式",{"2":{"167":1}}],["网页资源服务器",{"2":{"27":1}}],["专门对外提供",{"2":{"27":2}}],["​​visibility",{"2":{"466":1}}],["​background",{"2":{"466":1}}],["​color​​​",{"2":{"466":1}}],["​\\t添加的文章少还好",{"2":{"596":1}}],["​\\t每次添加文章过程",{"2":{"596":1}}],["​\\t\\tsearch",{"2":{"530":1}}],["​\\t\\ttolocaleuppercase",{"2":{"530":1}}],["​\\t\\t\\t\\t\\t\\t如果要",{"2":{"141":1}}],["​\\t\\t\\t\\t\\t受控组件也可以用于描述内部状态由传入",{"2":{"141":1}}],["​\\t都不会影响原字符串",{"2":{"530":1}}],["​\\t节流",{"2":{"520":1}}],["​\\t防抖",{"2":{"520":1}}],["​\\t以",{"2":{"234":1}}],["​\\t解决方法",{"2":{"234":1}}],["​\\t先执行ssh",{"2":{"234":1}}],["​\\t",{"2":{"137":1}}],["​",{"2":{"27":2,"137":7,"140":3,"146":3,"466":1}}],["六",{"0":{"27":1,"52":1,"308":1,"412":1,"461":1,"467":1},"1":{"28":1,"29":1,"468":1},"2":{"302":6}}],["目前常用的前端模块化规范有commonjs",{"2":{"549":1}}],["目前6个为当前的主流",{"2":{"15":2}}],["目录下的所有文件夹",{"2":{"599":2}}],["目录约定",{"2":{"488":1}}],["目录作为模块",{"2":{"26":1}}],["目标阶段",{"2":{"528":1}}],["目标版本",{"2":{"440":2}}],["目标仓库地址",{"2":{"396":2}}],["目的主机路径",{"2":{"59":2}}],["开始的",{"2":{"572":1}}],["开始占用任务空间",{"2":{"493":2}}],["开始切片并上传",{"2":{"14":1}}],["开头就变成了私有属性",{"2":{"270":2}}],["开头的路径标识符",{"2":{"26":1}}],["开发中如何选择key",{"2":{"147":2}}],["开启状态",{"2":{"520":2}}],["开启边界触发",{"2":{"519":2}}],["开启strictnullchecks",{"2":{"434":2}}],["开启该模式有助于发现并处理可能为undefined的赋值",{"2":{"434":1}}],["开启交互模式",{"2":{"210":1}}],["开启交互模式git",{"2":{"210":1}}],["开启定时器",{"2":{"147":4}}],["开启",{"0":{"164":1},"2":{"134":1}}],["开启非纯管道方式二",{"2":{"108":2}}],["开机启动",{"2":{"54":2}}],["或者promise",{"2":{"492":1}}],["或者更好的体验",{"2":{"487":1}}],["或者执行npm",{"2":{"421":1}}],["或者是提供的初始值",{"2":{"378":1}}],["或者使用",{"2":{"205":1}}],["或者",{"0":{"340":1},"2":{"205":1,"432":1,"615":1}}],["或是",{"2":{"150":1}}],["或父组件重新render触发",{"2":{"147":2}}],["或父组件render触发",{"2":{"147":2}}],["或",{"2":{"26":1,"61":2,"130":1,"205":3,"235":2,"279":2,"316":2,"318":2,"346":2,"440":2,"474":2,"477":1,"478":2,"479":1,"572":1}}],["时按0处理",{"2":{"532":1}}],["时且小于起始索引时",{"2":{"532":1}}],["时间的字符串",{"2":{"533":1}}],["时间复杂度为",{"2":{"292":2}}],["时间格式化",{"0":{"268":1}}],["时显示",{"2":{"121":4}}],["时可不需要这个接口",{"2":{"46":2}}],["时",{"2":{"26":1,"99":1,"271":1,"479":1}}],["只拷贝对象自身的可枚举的属性",{"2":{"527":2}}],["只拷贝一层",{"2":{"527":1}}],["只读常量",{"2":{"515":1}}],["只读属性",{"2":{"406":1,"412":2}}],["只是影响元素的外观",{"2":{"466":1}}],["只需要将编码后的字符串嵌入到html或css代码中即可",{"2":{"485":1}}],["只需要修改提交的内容而不需要改变提交信息",{"2":{"213":1}}],["只需一次推送",{"2":{"211":1}}],["只能保证指针固定",{"2":{"515":1}}],["只能在类内部使用",{"2":{"270":1}}],["只能在标签内部使用",{"2":{"121":2}}],["只能创建文件",{"2":{"18":1}}],["只调用一次",{"2":{"109":6}}],["只获取直属投影组件",{"2":{"106":2}}],["只进不出",{"2":{"101":1}}],["只要使用2次以上就抽离",{"2":{"571":2}}],["只要大于0字节就抽离",{"2":{"571":4}}],["只要两边类型不一致",{"2":{"512":1}}],["只要其中有一步可以解析成功",{"2":{"450":1}}],["只要有一个为",{"2":{"318":2}}],["只要p1",{"2":{"314":1}}],["只要参数有obj",{"2":{"272":2}}],["只要对象满足某些条件即可",{"2":{"272":1}}],["只要某个组件触发了以上中的一个",{"2":{"111":1}}],["只要是angular",{"2":{"80":2}}],["只要配置成功了",{"2":{"43":2}}],["只会在空白处换行",{"2":{"197":2}}],["只会显示一个ng",{"2":{"121":2}}],["只会出现在",{"2":{"80":2}}],["只会执行一次",{"2":{"26":1}}],["只有等执行完才会打开节流阀执行下一个事件",{"2":{"518":1}}],["只有用户需要查看某张图片时才会被加载",{"2":{"486":1}}],["只有被列出来的npm包才会被包含进来",{"2":{"438":1}}],["只有typeroots下面的包才会被包含进来",{"2":{"438":1}}],["只有需要编译的文件少时才会用到",{"2":{"414":2}}],["只有百度后面有地图两字的才满足要求",{"2":{"350":2}}],["只有当a为undefined或null才会进行赋值",{"2":{"252":1}}],["只有当a为undefined或null才会进行赋值let",{"2":{"252":1}}],["只有单词中有建议换行符才会换行",{"2":{"197":2}}],["只有一个根标签",{"2":{"137":1}}],["只有一个占位符可省略数组括号",{"2":{"38":2}}],["只有lo网卡",{"2":{"62":1}}],["只有lo网卡docker",{"2":{"62":1}}],["导致确定按钮事件没触发",{"2":{"610":2}}],["导致外层函数执行完变量不会被释放",{"2":{"536":1}}],["导出的对象以module",{"2":{"25":1}}],["导入辅助工具函数",{"2":{"440":2}}],["导入其他的ngmodule",{"2":{"78":1}}],["导入",{"2":{"20":1}}],["第二次",{"2":{"559":2}}],["第二秒执行",{"2":{"525":2}}],["第一次执行顺序",{"2":{"559":2}}],["第一次运行",{"2":{"541":2}}],["第一次自执行完",{"2":{"519":2}}],["第一秒执行",{"2":{"525":4}}],["第一步完成后",{"2":{"456":1}}],["第一个div只是用于承载",{"2":{"121":2}}],["第一个2m",{"2":{"15":2}}],["第三方库",{"2":{"513":1}}],["第三方",{"2":{"80":2}}],["第三方模块记载机制",{"2":{"26":1}}],["第三方模块",{"2":{"23":1}}],["优雅降级",{"2":{"487":1}}],["优雅降级和渐进增强",{"0":{"487":1}}],["优先级高",{"2":{"471":1}}],["优先处理靠近视口的块",{"2":{"463":1}}],["优先从缓存中加载",{"2":{"26":1}}],["优胜劣败",{"2":{"308":2}}],["优化大量图片的加载方法",{"0":{"486":1}}],["优化后",{"2":{"245":2,"541":2}}],["优化前",{"2":{"245":2}}],["优化开发体验",{"2":{"149":1}}],["优化访问方式",{"2":{"22":1}}],["优点和应用",{"0":{"48":1}}],["优点",{"2":{"0":1}}],["映射列表",{"2":{"433":2}}],["映射服务器文件路径",{"2":{"22":2}}],["映射用户",{"2":{"12":2}}],["`bg",{"2":{"614":4}}],["`export",{"2":{"599":2}}],["`xl",{"2":{"586":4}}],["`子类中的run方法",{"2":{"410":2}}],["`父类中的run方法",{"2":{"410":2}}],["`大家好",{"2":{"404":2,"406":6}}],["`dfa2332",{"2":{"345":2}}],["`$",{"2":{"294":2,"373":2,"409":2,"410":2,"578":2,"610":6}}],["`fibonacci",{"2":{"285":2}}],["`账号$",{"2":{"159":4}}],["`h1",{"2":{"84":2}}],["`update",{"2":{"37":4}}],["`insert",{"2":{"36":4}}],["`npm",{"2":{"34":1,"571":2}}],["`",{"2":{"21":12,"36":4,"37":4,"46":4,"84":6,"89":4,"90":4,"91":4,"92":4,"93":4,"95":8,"96":8,"108":4,"113":8,"116":8,"119":4,"121":12,"122":4,"123":4,"126":4,"130":8,"285":2,"294":2,"345":2,"346":12,"347":8,"349":4,"350":4,"373":2,"404":2,"406":6,"409":2,"410":6,"414":2,"571":2,"577":4,"578":2,"586":2,"599":22,"614":4}}],["动物在叫~",{"2":{"271":2,"411":2}}],["动态规划实现",{"2":{"285":2}}],["动态组件一定要声明entrycomponents",{"2":{"113":1}}],["动态组件都不需要entrycomponents了",{"2":{"113":1}}],["动态组件",{"0":{"113":1}}],["动态响应内容",{"0":{"21":1}}],["动漫",{"2":{"7":6}}],["8px",{"2":{"603":2}}],["83",{"2":{"578":2}}],["874",{"2":{"578":2}}],["875",{"2":{"578":4}}],["854",{"2":{"578":2}}],["82",{"2":{"578":2}}],["81",{"2":{"370":2,"578":2}}],["888",{"2":{"318":6,"319":10,"577":2}}],["8888",{"2":{"22":8,"43":4}}],["8888888",{"2":{"232":2}}],["888888",{"2":{"18":2}}],["8wekyb3d8bbwe",{"2":{"231":2}}],["8fc6389",{"2":{"210":2}}],["8em",{"2":{"185":2}}],["8|",{"2":{"107":4}}],["800",{"2":{"493":2,"494":2}}],["800px",{"2":{"168":4,"170":4}}],["8082",{"2":{"64":4}}],["8081",{"2":{"64":4}}],["8080",{"2":{"21":2,"64":8,"572":2}}],["80",{"2":{"20":2,"21":2,"28":4,"29":8,"30":4,"42":4,"577":2,"578":2,"580":2}}],["8",{"0":{"91":1,"258":1,"347":1,"433":1},"1":{"348":1},"2":{"20":4,"21":2,"22":8,"282":4,"285":2,"288":2,"330":2,"340":2,"342":4,"365":2,"370":2,"440":2,"491":2,"555":2,"578":2,"613":2}}],["不删除源文件",{"2":{"613":2}}],["不相对于屏幕视口定位",{"2":{"605":1}}],["不相等",{"2":{"257":2,"322":2}}],["不得不说当问题搞得人想撞墙的时候",{"2":{"594":1}}],["不生效",{"2":{"589":2}}],["不生成输出文件",{"2":{"440":2}}],["不生成编译后的文件",{"2":{"414":2}}],["不匹配则报错",{"2":{"563":1}}],["不传函数",{"2":{"540":2}}],["不可以",{"2":{"533":1}}],["不可以共享",{"2":{"522":1}}],["不复制对象本身",{"2":{"527":1}}],["不主动删除一直存在",{"2":{"522":1}}],["不同于",{"2":{"589":2}}],["不同端口号下",{"2":{"522":1}}],["不同类型的任务可以分属于不同的队列",{"2":{"448":1}}],["不同类型会转为相同类型再比较\\t",{"2":{"257":2}}],["不受外部影响",{"2":{"516":1}}],["不与任何值相等",{"2":{"512":1}}],["不写",{"2":{"489":1}}],["不适合大型图片",{"2":{"485":1}}],["不再与服务器发生通讯",{"2":{"471":1}}],["不影响布局",{"2":{"466":1}}],["不一定是一一对应的",{"2":{"459":1}}],["不行",{"2":{"448":1}}],["不然所有可能为null",{"2":{"434":1}}],["不允许",{"2":{"440":2,"514":2}}],["不允许不明确类型的this",{"2":{"414":2}}],["不允许隐式的any类型",{"2":{"414":2}}],["不允许在被子组件修改",{"2":{"111":1}}],["不返回或返回undefined",{"2":{"400":2}}],["不记录分组",{"2":{"346":2}}],["不区分大小写",{"2":{"345":2}}],["不包含",{"2":{"318":2}}],["不是则自动转为字符串",{"2":{"509":2}}],["不是",{"2":{"316":2}}],["不是一个合法的数字",{"2":{"302":2}}],["不使用",{"2":{"610":2}}],["不使用定时器没反应",{"2":{"584":2}}],["不使用柯里化",{"2":{"540":2}}],["不使用乘法符号乘法函数",{"0":{"297":1}}],["不使用额外变量交换",{"2":{"287":2}}],["不加",{"2":{"259":2}}],["不全等",{"2":{"257":2}}],["不知道怎么叫",{"2":{"245":2}}],["不便于管理",{"2":{"205":1}}],["不支持",{"2":{"194":1,"514":2}}],["不支持跨域",{"2":{"42":1}}],["不要过度使用ref",{"2":{"146":1}}],["不要写引号",{"2":{"137":1}}],["不用必须确保每个dom",{"2":{"125":1}}],["不会生效原因",{"2":{"615":1}}],["不会阻塞",{"2":{"456":1}}],["不会阻塞其他执行逻辑的执行",{"2":{"240":1}}],["不会对空数组进行检测",{"2":{"359":1,"367":1}}],["不会记录此原子组",{"2":{"346":1}}],["不会记录此原子组let",{"2":{"346":1}}],["不会立即执行",{"2":{"262":2}}],["不会自动类型转换",{"2":{"257":2}}],["不会删除本地不存在的远程分支",{"2":{"205":1}}],["不会更新本地分支和远程分支之间的关联关系",{"2":{"205":1}}],["不会导致内存泄漏",{"2":{"125":1}}],["不会执行变更检测",{"2":{"108":1}}],["不太好使",{"2":{"118":2}}],["不改变引用没有用",{"2":{"108":2}}],["不进不出",{"2":{"101":1}}],["不推荐",{"2":{"92":2,"96":1}}],["不常用",{"2":{"88":2}}],["不能为空`",{"2":{"610":2}}],["不能在声明前访问",{"2":{"516":1}}],["不能控制指向的数据结构",{"2":{"515":1}}],["不能同步操作",{"2":{"497":1}}],["不能访问",{"2":{"497":1}}],["不能单独存在",{"2":{"443":1}}],["不能修改",{"2":{"406":2}}],["不能修改class",{"2":{"406":2}}],["不能直接赋值给其他类型\\t",{"2":{"400":2}}],["不能直接使用foreach",{"2":{"243":1}}],["不能被其他数整除的",{"2":{"365":2}}],["不能返回自身promise",{"2":{"315":2}}],["不能调用数组的方法",{"2":{"263":2}}],["不能用在普通函数上",{"2":{"240":1}}],["不能指定端口",{"2":{"62":2}}],["不能创建路径",{"2":{"18":1}}],["不指定默认就是网桥模式",{"2":{"62":2}}],["不指定是root",{"2":{"61":2}}],["不需要加载操作系统os内核",{"2":{"48":1}}],["不具有安全性",{"2":{"41":1}}],["不存在则插入",{"2":{"7":2}}],["ws",{"2":{"589":2}}],["w3c",{"2":{"448":1}}],["w",{"2":{"346":10,"544":2}}],["wq",{"2":{"210":1}}],["was",{"2":{"230":2}}],["watch后面",{"2":{"554":1}}],["watch拼接到前者的",{"2":{"554":1}}],["watch",{"2":{"158":2,"554":1}}],["warning",{"2":{"77":1,"108":1,"112":1,"113":4,"117":1,"121":1,"123":1,"128":1,"132":1,"146":1,"497":1,"596":1,"600":1,"605":1}}],["warningcount",{"2":{"36":2}}],["wellknown",{"2":{"414":4}}],["wearerequired",{"2":{"396":2}}],["weather",{"2":{"143":4}}],["weekday",{"2":{"268":2}}],["webpack又基于node之上",{"2":{"432":1}}],["webpack会把你的代码转换成在所有浏览器中可运行的代码",{"2":{"429":1}}],["webpack",{"2":{"417":8,"418":17,"420":4,"535":1,"548":3}}],["webpack整合",{"0":{"415":1},"1":{"416":1,"417":1,"418":1,"419":1,"420":1,"421":1,"422":1,"423":1}}],["webworker",{"2":{"414":6,"431":1}}],["webkit",{"2":{"176":6,"177":8}}],["web",{"0":{"20":1,"495":1},"2":{"19":1,"20":1,"27":2,"130":1}}],["wins",{"2":{"450":1}}],["window",{"0":{"615":1},"2":{"249":4,"262":4,"333":2,"334":4,"357":2,"426":2,"429":1,"432":1,"438":1,"512":2,"535":1,"541":12,"551":1,"574":4,"577":2,"584":8,"614":2,"615":1}}],["windowsapps",{"2":{"231":2}}],["windows",{"2":{"231":2,"450":4}}],["windows为cmd",{"2":{"61":2}}],["wind",{"2":{"143":6}}],["within",{"2":{"586":2}}],["with",{"2":{"396":10}}],["width=",{"2":{"178":4,"478":4}}],["width",{"2":{"92":6,"98":2,"113":2,"168":4,"170":2,"177":6,"178":2,"179":2,"189":2,"190":6,"195":6,"201":2,"481":2,"482":2,"489":6,"490":2,"541":2,"551":8,"577":8,"578":32,"603":10,"610":2,"611":4}}],["www",{"2":{"61":2,"341":2,"346":12,"347":12,"349":12,"350":4,"532":8,"573":2}}],["worker的基础上增加了离线缓存的能力",{"2":{"497":1}}],["worker那么它可以拦截当前网站所有的请求",{"2":{"496":1}}],["worker",{"0":{"495":1,"496":1},"2":{"495":15,"496":1,"497":1}}],["worker中执行",{"2":{"492":1}}],["workers技术",{"2":{"492":1}}],["work",{"2":{"151":2,"152":2,"153":2}}],["works",{"2":{"102":2,"105":2,"106":2,"114":2}}],["workdir",{"2":{"61":4}}],["world",{"2":{"51":2,"55":2,"301":6,"334":2,"524":2}}],["wrapper",{"2":{"490":2}}],["wrapperloading",{"2":{"159":4}}],["wrap",{"2":{"482":4,"610":2}}],["wrapcls",{"2":{"113":4}}],["wrong",{"2":{"36":2}}],["write",{"2":{"298":2,"334":4}}],["writehead",{"2":{"20":2}}],["writefilesync",{"2":{"599":2}}],["writefile",{"2":{"18":4}}],["wheel",{"2":{"615":2}}],["where",{"2":{"4":2,"37":4,"38":4}}],["white",{"2":{"176":2,"197":2,"199":4,"491":10,"577":2,"611":2}}],["while",{"2":{"15":4,"260":4,"282":4,"290":4,"291":2,"292":8,"294":2,"298":4,"300":4,"301":4,"543":2,"544":6}}],["抵消路劲",{"2":{"17":2}}],["jobid",{"2":{"427":4}}],["jobs",{"2":{"396":2}}],["join",{"2":{"17":2,"22":8,"283":2,"302":8,"371":2,"372":4,"539":2,"599":4}}],["jpeg",{"2":{"333":2}}],["jpg",{"2":{"86":2,"333":2,"374":4}}],["j+1",{"2":{"287":10}}],["j++",{"2":{"287":2,"288":2,"292":6,"301":4,"302":2,"316":2,"319":2}}],["j",{"2":{"287":14,"288":8,"291":16,"292":20,"301":28,"302":6,"316":6,"319":8,"328":8}}],["jetbrainsmono",{"2":{"231":2}}],["jerry",{"2":{"144":2}}],["java",{"2":{"393":2}}],["javascriptmodule",{"2":{"573":1}}],["javascript主线程的独立线程",{"2":{"497":1}}],["javascriptconst",{"2":{"362":1,"572":2}}],["javascript+",{"2":{"347":1}}],["javascriptfunction",{"2":{"318":1}}],["javascriptlet",{"2":{"301":2,"340":1,"342":1,"345":1,"346":1,"348":1,"349":1,"350":1}}],["javascript是单线程执行语言",{"2":{"237":1}}],["javascript实现异步",{"0":{"237":1},"1":{"238":1,"239":1,"240":1,"241":1,"242":1,"243":1}}],["javascript",{"0":{"568":1},"2":{"129":2,"139":6,"299":1,"301":1,"341":1,"344":1,"393":2,"440":4,"483":1,"543":2,"544":2,"560":1}}],["jandedobbeleer",{"2":{"222":2}}],["juejin",{"2":{"211":12}}],["justify",{"2":{"167":4,"168":4,"170":2,"174":7,"474":6,"586":4,"587":4,"603":4}}],["jumper",{"2":{"156":2}}],["jwt",{"0":{"43":1},"2":{"43":23}}],["js|css",{"2":{"613":2}}],["js漏了导入并使用descriptionsitem",{"2":{"609":2}}],["jsmounted",{"2":{"577":1,"615":1}}],["jsmarkforcheck",{"2":{"112":1}}],["js的",{"0":{"573":1}}],["js主要解析和比对",{"2":{"563":1}}],["jswindow",{"2":{"551":1}}],["js采用了该规范",{"2":{"549":1}}],["js运行的环境",{"2":{"535":1}}],["jsnitro",{"2":{"590":1}}],["jsnumber",{"2":{"533":1}}],["jsnew",{"2":{"239":2}}],["jslocalstorage",{"2":{"523":1}}],["jslet",{"2":{"38":2,"238":1,"252":1,"279":1,"308":1,"311":1,"313":1,"319":1,"321":1,"323":1,"325":1,"381":1,"383":1,"385":1,"389":1,"510":1,"523":1,"527":1,"532":1,"539":1}}],["jsparseint",{"2":{"509":1}}],["jspm",{"2":{"414":2}}],["js继承有哪些方式",{"0":{"501":1},"1":{"502":1,"503":1,"504":1}}],["js执行",{"2":{"456":1,"564":1}}],["js是一门单线程的语言",{"2":{"447":1}}],["js和",{"2":{"439":1}}],["js文件",{"2":{"439":1}}],["js后缀的文件也会被typescript进行编译",{"2":{"437":1}}],["js配置文件",{"0":{"423":1}}],["js用来使老版本的浏览器支持新版es语法",{"2":{"422":1}}],["js详细配置",{"2":{"418":1}}],["jsboolean",{"2":{"399":1}}],["js类型",{"0":{"399":1}}],["jsvue",{"2":{"375":1}}],["jsvar",{"2":{"288":1,"307":1,"363":1,"364":1,"384":1,"389":1}}],["js常用的求交集",{"0":{"320":1},"1":{"321":1,"322":1,"323":1,"324":1,"325":1,"326":1,"327":1,"328":1}}],["jssessionstorage",{"2":{"523":1}}],["jssettimeout",{"2":{"238":1}}],["jsstatic",{"2":{"313":1}}],["jsthen",{"2":{"308":1,"310":1,"311":1}}],["jsclass",{"2":{"303":1,"304":1,"315":1,"502":1}}],["jsconst",{"2":{"13":1,"16":1,"17":2,"18":1,"20":1,"21":1,"22":2,"25":2,"28":1,"29":2,"34":1,"42":1,"43":1,"46":1,"249":1,"250":1,"265":2,"268":1,"293":1,"296":1,"314":1,"316":2,"329":1,"331":1,"332":1,"333":1,"357":1,"364":1,"371":1,"372":1,"373":1,"374":1,"380":1,"382":1,"393":1,"507":1,"536":1,"539":2,"540":1,"551":1}}],["js递归实现",{"2":{"300":1}}],["js解释器会自动将其转换为字符串",{"2":{"265":1}}],["jsfn2",{"2":{"262":1}}],["jsfn",{"2":{"262":1}}],["jsfunction",{"2":{"146":1,"246":1,"247":1,"262":1,"272":1,"278":1,"281":2,"284":1,"287":1,"289":1,"290":1,"291":1,"292":1,"294":1,"295":1,"298":1,"302":2,"370":1,"498":1,"499":1,"500":1,"503":1,"519":1,"524":1,"525":1,"536":2,"541":1,"544":2}}],["js==",{"2":{"257":1}}],["js+",{"2":{"253":1}}],["jsarr11",{"2":{"385":1}}],["jsarray",{"2":{"360":1,"368":1}}],["jsarr",{"2":{"288":1,"378":1,"388":1}}],["jsa",{"2":{"251":1}}],["jsasync",{"2":{"240":1,"243":5}}],["jsdata",{"2":{"158":1}}],["jsdb",{"2":{"7":1}}],["jsimport",{"2":{"157":1,"577":1}}],["jsif",{"2":{"129":1,"259":1,"306":1,"309":1}}],["jsexport",{"2":{"156":1,"551":1,"585":1,"589":1}}],["jsexports",{"2":{"9":1,"10":1,"11":1}}],["js\\t",{"2":{"139":1}}],["js表达式",{"2":{"137":1,"258":1}}],["js语句",{"2":{"137":1}}],["jsxclass",{"2":{"145":1}}],["jsxconst",{"2":{"137":1}}],["jsxfunction",{"2":{"144":1}}],["jsx",{"2":{"143":1,"144":1,"439":1,"440":4}}],["jsx语法规则",{"2":{"137":1}}],["js应用是通过引导根模块",{"2":{"82":1}}],["js该数组为当前模块提供一系列服务该数组为当前模块提供一系列服务",{"2":{"81":1}}],["js1",{"2":{"79":1,"80":1}}],["json添加脚本执行命令",{"0":{"598":1}}],["json记录了映射关系",{"2":{"563":1}}],["json重新生成文件",{"2":{"440":2}}],["json全解析",{"0":{"440":1}}],["json选项的解释",{"2":{"425":1}}],["json是编译typescript的配置文件",{"2":{"425":1}}],["json配置",{"0":{"420":1}}],["json中加上build命令",{"2":{"418":2}}],["json中设置",{"2":{"134":2}}],["json文件",{"2":{"416":1,"418":4}}],["json详细配置",{"2":{"414":1}}],["jsonpipe",{"2":{"132":1}}],["json",{"0":{"425":1},"1":{"426":1,"427":1,"428":1,"429":1,"430":1,"431":1,"432":1,"433":1,"434":1,"435":1,"436":1,"437":1,"438":1,"439":1,"440":1},"2":{"43":2,"46":2,"157":4,"211":10,"224":4,"227":2,"229":1,"231":2,"414":3,"419":1,"432":2,"440":1,"527":4,"563":1,"564":1,"573":3,"590":1,"599":2}}],["jsonwebtoken",{"2":{"43":4}}],["js",{"0":{"248":1},"1":{"249":1,"250":1},"2":{"12":2,"13":7,"16":1,"25":8,"29":1,"30":6,"35":1,"36":1,"37":1,"122":1,"137":1,"139":12,"140":1,"147":1,"159":1,"168":1,"220":5,"241":1,"242":1,"245":1,"254":1,"255":1,"256":1,"260":1,"261":1,"263":1,"264":1,"265":1,"266":1,"267":1,"269":1,"270":2,"271":1,"276":1,"279":1,"282":1,"283":1,"285":1,"292":1,"293":1,"296":1,"297":1,"299":1,"303":2,"305":1,"307":1,"312":1,"314":2,"318":1,"319":1,"322":1,"324":1,"326":1,"327":1,"328":1,"330":1,"335":1,"365":1,"378":1,"414":3,"418":5,"422":2,"423":1,"433":4,"440":2,"444":1,"445":1,"447":1,"448":2,"449":1,"456":5,"465":2,"477":1,"488":1,"493":1,"494":1,"495":4,"512":1,"513":3,"519":1,"520":1,"526":1,"527":1,"531":1,"535":1,"542":1,"543":3,"548":1,"555":1,"556":1,"559":1,"563":1,"570":3,"571":1,"573":4,"574":1,"577":2,"578":3,"579":1,"580":1,"584":2,"586":1,"588":1,"589":1,"599":1,"612":2,"613":3}}],["这行代码在作怪",{"2":{"605":1}}],["这种方式可以大幅减少初始页面加载时间",{"2":{"486":1}}],["这种对属性读取或设置的属性被称为属性的存取器",{"2":{"407":1}}],["这对于高流量网站来说非常重要",{"2":{"485":1}}],["这些元素的内容可以通过",{"2":{"483":1}}],["这些提交",{"2":{"205":1}}],["这一步完成后",{"2":{"458":1}}],["这又带来了偏差",{"2":{"448":1}}],["这时还要用到babel来做转换",{"2":{"422":1}}],["这时就会报错",{"2":{"135":1}}],["这就是",{"2":{"456":1}}],["这就是css",{"2":{"456":1}}],["这就是单向数据流",{"2":{"111":1}}],["这就称为方法的重写",{"2":{"410":1}}],["这样配置到达",{"2":{"589":2}}],["这样的路径下",{"2":{"573":1}}],["这样能够更精确地控制元素的尺寸和定位",{"2":{"475":1}}],["这样一来",{"2":{"447":1}}],["这样在编译过程中",{"2":{"431":1}}],["这样就不需要定义一个变量就必须赋有初始值",{"2":{"427":1}}],["这样就构成了一条原型链",{"2":{"274":1}}],["这样我们只需要创建一个属性",{"2":{"275":1}}],["这里主要记录编程遇到的问题",{"2":{"616":1}}],["这里需要重新处理x",{"2":{"580":2}}],["这里还可以尝试一些其他的测试用例",{"2":{"301":1}}],["这里我填上我安装的是jetbrainsmono",{"2":{"230":1}}],["这里使用的构造提供的模版",{"2":{"126":2}}],["这本书让我感受到",{"2":{"181":1}}],["这会非常有用",{"2":{"122":2}}],["这个设置是非常重要的",{"2":{"572":1}}],["这个路径下",{"2":{"572":1}}],["这个属性的作用主要是为了适应应用被部署在服务器上的子目录下的情况",{"2":{"572":1}}],["这个属性值的默认值为",{"2":{"572":1}}],["这个属性叫做",{"2":{"274":1}}],["这个方法",{"2":{"509":1}}],["这个例子中",{"2":{"301":1}}],["这个根组件通常叫做",{"2":{"82":2}}],["这个容器网卡也没有啦",{"2":{"63":1}}],["这个容器网卡也没有啦docker",{"2":{"63":1}}],["这个中间件",{"2":{"43":2}}],["这次错误是由",{"2":{"43":2}}],["这是默认值",{"2":{"573":1}}],["这是因为",{"2":{"456":1}}],["这是因为下载和解析",{"2":{"456":1}}],["这是因为它运行在浏览器的渲染主线程中",{"2":{"447":1}}],["这是递归的请求",{"2":{"450":1}}],["这是一个非常有用的选项",{"2":{"433":1}}],["这是一个自定义的title",{"2":{"418":2}}],["这是一个有权限的",{"2":{"43":2}}],["这是葡萄",{"2":{"123":2}}],["这是梨",{"2":{"123":2}}],["这是苹果",{"2":{"123":2}}],["这是",{"2":{"123":6,"464":1}}],["这是单个分片的",{"2":{"15":2}}],["这四个都可以成功",{"2":{"16":2}}],["拼接后面的路径需要写正斜杠",{"2":{"16":1}}],["坑点三",{"0":{"607":1}}],["坑点二",{"0":{"606":1}}],["坑点一",{"0":{"605":1}}],["坑点",{"2":{"16":1,"396":2,"602":1}}],["问题二",{"2":{"468":1}}],["问题一",{"2":{"303":1,"468":1}}],["问题",{"2":{"16":1}}],["读书摘要",{"0":{"181":1},"1":{"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1,"190":1,"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"198":1,"199":1,"200":1,"201":1,"202":1,"203":1}}],["读取",{"2":{"599":4}}],["读取数据",{"2":{"523":2}}],["读取属性的方法叫做setter方法",{"2":{"407":1}}],["读取对象属性时",{"2":{"275":1}}],["读取成功",{"2":{"16":2}}],["读取失败",{"2":{"16":4,"22":4}}],["读取文件",{"0":{"16":1},"1":{"17":1}}],["读写操作频繁",{"2":{"0":1}}],["竞赛等出一个执行完毕的请求",{"2":{"15":2}}],["rback3",{"2":{"578":2}}],["rback2",{"2":{"578":2}}],["rback1",{"2":{"578":2}}],["rules",{"2":{"418":2,"423":2}}],["runtimechunk",{"2":{"571":2}}],["runs",{"2":{"396":2}}],["run之后的参数替换",{"2":{"61":2}}],["running",{"2":{"30":2,"42":2,"43":2,"46":2}}],["run",{"0":{"562":1},"1":{"563":1,"564":1},"2":{"28":2,"29":4,"51":2,"55":2,"56":2,"57":4,"59":2,"61":10,"62":4,"63":2,"64":8,"395":2,"396":4,"410":4,"411":4,"421":1,"493":6,"563":1,"564":1}}],["rf",{"2":{"395":2}}],["rsa",{"2":{"232":2,"233":1,"234":2,"235":4,"396":4}}],["r",{"2":{"206":2,"208":4,"578":4}}],["rgb",{"2":{"190":6,"198":2,"458":1}}],["rgba",{"2":{"177":2,"179":6,"191":1,"195":6,"585":4}}],["r=",{"2":{"178":2}}],["ratio",{"2":{"578":32}}],["range",{"2":{"574":6}}],["randomid",{"2":{"357":4}}],["random",{"2":{"267":8,"288":2}}],["radix",{"2":{"509":4}}],["radialgradient",{"2":{"478":1}}],["radial",{"2":{"478":1}}],["radius",{"2":{"177":2,"185":2,"188":8,"195":8,"481":2,"577":2,"578":8,"603":6}}],["radio",{"2":{"123":8}}],["race",{"0":{"314":1},"2":{"15":2,"314":6,"315":2}}],["rights",{"2":{"234":2}}],["right",{"2":{"113":2,"179":2,"184":2,"186":2,"189":2,"190":2,"195":8,"289":6,"299":18,"300":20,"474":2,"478":1,"479":1,"490":2}}],["rm",{"2":{"56":8,"62":2,"208":4,"395":2}}],["rmi",{"2":{"55":2}}],["road",{"2":{"318":6,"319":10}}],["routes",{"2":{"572":1,"590":3}}],["router的路由路径",{"2":{"572":1}}],["router",{"2":{"29":1,"30":10,"46":10,"572":5,"573":2}}],["round",{"2":{"267":4,"578":4}}],["rotate",{"2":{"179":2,"193":2,"195":4}}],["role=",{"2":{"113":2}}],["rollup",{"2":{"22":6}}],["rows",{"2":{"165":7,"168":2,"170":2}}],["row",{"2":{"36":4,"166":2,"172":14,"173":6,"372":4}}],["rowdatapacket",{"2":{"34":2,"35":4}}],["rootdirs",{"2":{"440":2}}],["rootdir",{"2":{"440":2}}],["rootnodes",{"2":{"113":2}}],["root",{"2":{"34":4,"84":2,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":2,"96":2,"108":2,"109":2,"116":4,"126":2,"130":2,"137":4,"139":4,"140":2,"214":2,"299":50,"300":20,"432":20,"544":8}}],["roolup",{"2":{"22":2}}],["ret进行扩展",{"2":{"554":1}}],["ret",{"2":{"554":1}}],["returnvalue",{"2":{"551":2}}],["return",{"2":{"12":4,"15":8,"16":4,"22":4,"34":2,"35":2,"36":4,"37":4,"38":4,"42":4,"43":4,"84":2,"107":2,"108":2,"113":4,"122":2,"239":10,"263":2,"264":2,"270":6,"278":2,"279":12,"281":8,"282":10,"283":6,"284":4,"285":6,"287":2,"288":2,"289":4,"290":2,"291":2,"292":10,"294":2,"295":4,"296":4,"297":8,"298":2,"299":12,"300":20,"301":4,"302":12,"308":6,"310":2,"311":4,"312":4,"313":2,"314":2,"315":10,"316":8,"318":24,"319":10,"326":6,"327":2,"362":2,"363":2,"364":2,"365":8,"370":2,"374":2,"378":2,"385":4,"388":1,"389":8,"393":2,"399":2,"407":2,"408":2,"412":2,"426":2,"493":6,"494":10,"512":4,"519":4,"520":10,"524":2,"527":8,"536":6,"539":16,"540":8,"541":10,"543":6,"544":6,"551":8,"571":2,"574":2,"577":8,"578":26,"583":4,"589":2,"599":10}}],["rem",{"2":{"488":1}}],["remotes",{"2":{"211":6}}],["remote",{"2":{"209":2,"211":18,"234":2}}],["removeeventlistener",{"2":{"574":2}}],["removechild",{"2":{"574":2}}],["removecomments",{"2":{"414":2,"440":2}}],["removeallranges",{"2":{"574":2}}],["removeaccount",{"2":{"159":2}}],["removeitem",{"2":{"523":4}}],["removedone",{"2":{"159":2}}],["remove",{"2":{"6":6,"570":3}}],["regbaidu1",{"2":{"347":4}}],["regbaidu",{"2":{"347":2}}],["reg1",{"2":{"346":2}}],["regulex",{"2":{"339":1}}],["regexper",{"2":{"339":1}}],["regexp",{"2":{"316":2,"319":4,"414":2,"506":1,"527":6,"578":2}}],["regexp类型转换成字符串",{"2":{"316":1}}],["reg",{"2":{"302":4,"341":12,"346":12,"347":12,"348":8,"350":12}}],["registry",{"2":{"55":8,"293":12}}],["registercombo",{"2":{"578":4}}],["registernode",{"2":{"578":6}}],["registeredge",{"2":{"578":4}}],["registerelements",{"2":{"577":2,"578":2}}],["register",{"2":{"9":2}}],["reverselinkedlist",{"2":{"298":4}}],["reverse",{"2":{"283":2,"302":4}}],["reversestring",{"2":{"283":8}}],["reject改变状态并执行回调函数",{"2":{"315":2}}],["rejected",{"2":{"303":6,"304":6,"305":2,"306":2,"307":2,"308":2,"309":2,"310":2,"311":2,"315":8}}],["reject",{"2":{"239":12,"242":4,"295":12,"303":8,"304":4,"307":6,"308":14,"309":8,"310":28,"311":16,"312":10,"313":12,"314":2,"315":36,"493":4,"494":4,"551":4}}],["rebase",{"2":{"205":1,"210":6,"213":2,"214":8,"217":2}}],["recognized",{"2":{"230":2}}],["rect",{"2":{"178":4,"478":2,"578":8}}],["recursive",{"2":{"46":2}}],["repaint",{"2":{"466":3,"577":2}}],["repeating",{"2":{"186":2}}],["repeat",{"2":{"165":2,"168":4,"170":4,"195":2,"199":2,"530":1,"551":2,"578":18}}],["replaceall",{"2":{"530":1}}],["replace",{"2":{"157":2,"302":12,"346":4,"347":2,"350":2,"530":1,"571":2,"572":1,"599":8}}],["repository",{"2":{"234":4}}],["repo",{"2":{"51":4,"211":2,"396":6}}],["real",{"2":{"590":2}}],["reason",{"2":{"303":6,"304":6,"307":4,"308":8,"312":4,"313":8,"314":4,"315":8}}],["react会根据",{"2":{"147":2}}],["react中的事件是通过事件委托方式处理的",{"2":{"146":1}}],["react使用的是自定义",{"2":{"146":1}}],["react解析组件标签",{"2":{"139":2,"140":1}}],["reactdom",{"2":{"137":2,"140":2,"143":2,"144":8,"145":2}}],["react",{"2":{"137":2,"139":4,"140":2,"141":5,"143":2,"144":2,"145":6,"147":2,"278":1,"440":4}}],["readme",{"2":{"602":1}}],["readdirsync",{"2":{"599":4}}],["readonly",{"2":{"406":1,"412":2,"574":4}}],["readasdataurl",{"2":{"335":4}}],["readasarraybuffer",{"2":{"15":2,"331":2,"333":2}}],["reading",{"0":{"586":1},"1":{"587":1},"2":{"318":6,"319":10,"588":1}}],["read",{"0":{"586":1},"1":{"587":1},"2":{"234":2,"577":2,"588":1}}],["readfile",{"2":{"16":6,"22":4}}],["reader",{"2":{"15":6}}],["render中的this",{"2":{"140":2}}],["render中的this指向mycomponent组件实例对象",{"2":{"140":2}}],["render在mycomponent的原型对象上",{"2":{"140":2}}],["render",{"2":{"114":14,"137":2,"139":4,"140":3,"143":2,"144":8,"145":2,"147":4,"455":1}}],["relative+fixed",{"2":{"479":1}}],["relative",{"2":{"189":2,"190":2,"195":4,"474":4,"490":2,"551":2}}],["relateoptions",{"2":{"157":4}}],["reload",{"2":{"73":2}}],["releases",{"2":{"66":2}}],["reduceright",{"2":{"540":2}}],["reduce与",{"2":{"316":2}}],["reduce",{"0":{"376":1},"1":{"377":1,"378":1,"379":1,"380":1,"381":1,"382":1,"383":1,"384":1,"385":1},"2":{"264":2,"316":2,"326":4,"327":2,"378":5,"380":2,"381":2,"382":2,"383":2,"384":2,"385":4,"539":8,"599":4}}],["redbox",{"2":{"192":1}}],["red",{"2":{"70":1,"124":2,"192":1,"347":8,"399":2,"457":1,"458":1,"481":2}}],["redis",{"2":{"55":2}}],["referenceerror",{"2":{"516":1}}],["ref1ow",{"2":{"465":2}}],["reflow",{"2":{"465":1}}],["reflect等",{"2":{"431":1}}],["reflect",{"2":{"318":2,"414":2}}],["ref=",{"2":{"145":8,"551":2}}],["refs",{"0":{"145":1},"2":{"145":2,"211":10}}],["ref",{"2":{"13":2,"130":2,"141":1,"334":4,"335":2,"614":4}}],["rest",{"2":{"599":2}}],["restart",{"2":{"56":2,"75":2}}],["resizehandler",{"2":{"615":6}}],["resizeobserver",{"2":{"615":10}}],["resize",{"0":{"615":1},"2":{"577":2,"584":13,"615":2}}],["res2",{"2":{"525":2}}],["res1",{"2":{"525":4}}],["resp",{"2":{"494":8}}],["response",{"2":{"335":6,"488":1}}],["resarr",{"2":{"295":16}}],["resave",{"2":{"42":2}}],["reset",{"2":{"108":8}}],["resolve改变状态并执行回调函数",{"2":{"315":2}}],["resolves",{"2":{"313":8,"315":8}}],["resolvecomponentfactory",{"2":{"113":2}}],["resolve",{"2":{"15":4,"239":11,"240":4,"242":2,"295":16,"303":8,"304":4,"307":6,"308":14,"309":8,"310":30,"311":16,"312":8,"313":12,"314":12,"315":36,"418":4,"493":6,"494":12,"525":8,"551":4,"571":4,"599":12}}],["results",{"2":{"494":8}}],["result",{"2":{"10":6,"15":2,"158":14,"239":26,"240":4,"263":6,"268":6,"282":10,"283":6,"292":12,"297":10,"302":8,"308":16,"309":16,"310":34,"311":10,"315":10,"331":6,"333":2,"335":2,"348":4,"365":2,"370":4,"384":4,"493":4,"574":4}}],["res",{"2":{"9":4,"10":6,"11":6,"12":16,"15":2,"20":8,"21":6,"22":16,"28":4,"29":29,"30":8,"34":8,"35":8,"36":14,"37":12,"38":8,"42":16,"43":16,"45":6,"46":8,"243":2,"295":16,"299":36,"302":22,"326":8,"346":4,"363":4,"493":8,"494":6,"578":10}}],["requestanimationframe",{"0":{"526":1},"2":{"477":1}}],["request",{"2":{"20":3,"21":2,"22":4,"494":6}}],["requestlist",{"2":{"15":8}}],["request=",{"2":{"15":2}}],["required",{"2":{"13":14,"113":2}}],["require",{"2":{"13":18,"16":2,"18":2,"20":2,"21":2,"22":12,"25":4,"26":2,"28":2,"29":4,"30":8,"34":2,"42":4,"43":10,"46":8,"418":6,"599":4}}],["req",{"2":{"9":4,"10":4,"11":8,"12":8,"20":2,"21":4,"22":16,"28":2,"29":47,"30":14,"42":22,"43":18,"46":10}}],["63",{"2":{"589":4}}],["69",{"2":{"578":2}}],["62",{"2":{"578":2}}],["627686574f57a31b328b63ab",{"2":{"7":2}}],["62767f841f41a9d7de748124",{"2":{"6":2}}],["6标准中新增的模块化规范",{"2":{"549":1}}],["656",{"2":{"578":2}}],["65",{"2":{"531":2}}],["655",{"2":{"183":2,"185":4}}],["678",{"2":{"578":2}}],["67",{"2":{"531":4}}],["67ms",{"2":{"526":1}}],["6deg",{"2":{"481":4}}],["6秒后打印的",{"2":{"238":2}}],["61",{"2":{"198":2}}],["68d",{"2":{"195":2}}],["60hz",{"2":{"526":1}}],["600",{"2":{"493":2,"494":2,"577":2}}],["60var",{"2":{"384":1}}],["60",{"2":{"362":4,"384":1,"445":1}}],["60deg",{"2":{"186":2,"195":2}}],["60606f",{"2":{"178":2}}],["666",{"2":{"585":2}}],["667",{"2":{"578":4}}],["66",{"2":{"186":4,"302":2,"531":2}}],["6px",{"2":{"177":2}}],["642",{"2":{"578":4}}],["640px",{"2":{"489":2}}],["64",{"2":{"66":2,"370":2,"507":2,"513":1}}],["6",{"0":{"89":1,"256":1,"345":1,"421":1,"431":1},"2":{"15":2,"36":2,"37":2,"38":2,"45":2,"137":1,"186":4,"282":8,"288":2,"299":10,"319":2,"330":2,"346":4,"348":2,"349":2,"363":2,"365":2,"370":2,"383":4,"393":2,"432":2,"440":2,"539":2,"578":12}}],["转换为",{"2":{"548":1,"551":1}}],["转换为数字",{"2":{"510":2}}],["转化结果",{"2":{"491":1}}],["转化为大写",{"2":{"132":1}}],["转化为小写",{"2":{"132":1}}],["转化为json才能移除密码",{"2":{"9":2}}],["转而等待",{"2":{"456":1}}],["转而执行后续代码",{"2":{"447":1}}],["转为数组获取元素",{"2":{"266":2}}],["转存为",{"2":{"43":2}}],["转成promise",{"2":{"15":2}}],["+sum",{"2":{"539":2}}],["+str",{"2":{"302":2}}],["+delay",{"2":{"519":2}}],["+date",{"2":{"108":2}}],["+data",{"2":{"16":2}}],["+出现在左边",{"2":{"510":2}}],["++i",{"2":{"512":2}}],["++this",{"2":{"512":2}}],["++a",{"2":{"510":2}}],["++",{"2":{"385":2}}],["++deep",{"2":{"282":2}}],["+1",{"2":{"295":2}}],["+obj",{"2":{"272":2}}],["+refs",{"2":{"211":6}}],["+req",{"2":{"20":4}}],["+err",{"2":{"16":4}}],["+=",{"2":{"15":4,"252":2,"263":2,"283":2,"297":2,"302":6,"578":4,"615":4}}],["+",{"2":{"15":24,"46":14,"84":4,"108":2,"113":4,"116":4,"197":1,"239":10,"252":2,"264":2,"267":4,"269":2,"281":2,"283":2,"285":4,"287":2,"288":4,"290":4,"291":4,"292":4,"294":2,"297":2,"298":2,"301":2,"302":18,"319":2,"341":6,"346":6,"347":7,"349":2,"350":4,"365":2,"378":2,"380":2,"382":2,"384":2,"385":2,"408":2,"412":6,"474":4,"475":5,"493":6,"494":6,"510":2,"539":16,"540":2,"578":14,"599":2,"610":2}}],["+i",{"2":{"5":2}}],["hw",{"2":{"524":6}}],["hh",{"2":{"400":2}}],["hhtml",{"2":{"346":6}}],["hstr",{"2":{"349":6}}],["hsl",{"2":{"198":2}}],["h",{"2":{"346":4,"349":2,"399":4,"400":4,"543":2}}],["hdstr",{"2":{"345":8}}],["hd",{"2":{"345":4}}],["hdjfaks35fjj",{"2":{"341":2}}],["hdjfaks34fjj",{"2":{"341":2}}],["hk",{"2":{"268":2}}],["hubcombo",{"2":{"578":4,"580":2}}],["hub",{"2":{"578":6}}],["husky",{"2":{"218":1,"220":2}}],["hue",{"2":{"193":2}}],["hyphens",{"2":{"197":5}}],["hi",{"2":{"235":1}}],["hidden",{"0":{"587":1},"2":{"176":4,"231":2,"482":8,"586":6,"587":2,"611":2}}],["highlight",{"2":{"125":6}}],["highlightdirective",{"2":{"125":2}}],["highlightcolor",{"2":{"124":4,"125":6}}],["h2",{"2":{"139":4,"140":4,"346":8,"347":16,"349":8}}],["h3",{"2":{"126":4,"349":8}}],["href=",{"2":{"335":2,"350":2}}],["hr",{"2":{"122":2}}],["halfheight",{"2":{"577":4}}],["halfwidth",{"2":{"577":4}}],["have",{"2":{"234":2}}],["handlescroll",{"2":{"614":4,"615":4}}],["handlecurrentchange",{"2":{"612":2}}],["handleclick",{"2":{"577":2}}],["handle",{"2":{"536":6}}],["handler",{"2":{"158":2,"574":6}}],["hangzhou",{"2":{"55":8}}],["hasownproperty",{"2":{"277":1,"319":2,"527":2}}],["hasown",{"0":{"277":1},"2":{"277":1}}],["has",{"2":{"265":2,"266":2,"296":4,"324":4}}],["hasview",{"2":{"126":10}}],["hash",{"2":{"14":1,"15":28,"210":2}}],["hat系列",{"2":{"70":1}}],["hexo博客源码没有备份",{"0":{"607":1}}],["help",{"2":{"433":2}}],["helloworldgenerator",{"2":{"524":4}}],["hello",{"2":{"51":2,"55":2,"137":2,"262":4,"272":2,"301":3,"334":2,"345":2,"399":2,"412":2,"414":2,"524":2}}],["heros",{"2":{"122":2}}],["heroes",{"2":{"108":16}}],["hero",{"2":{"108":20}}],["height=",{"2":{"178":4,"478":4}}],["height",{"2":{"91":4,"92":6,"113":2,"168":4,"170":2,"177":4,"178":2,"179":2,"180":2,"189":2,"190":8,"195":6,"198":2,"202":2,"474":1,"475":2,"481":2,"482":2,"490":2,"551":8,"577":10,"578":32,"603":6}}],["heads",{"2":{"211":10}}],["head~3",{"2":{"210":2}}],["head",{"2":{"102":4,"105":12,"298":18,"302":4,"303":4}}],["headerbg",{"2":{"614":8}}],["headers",{"2":{"45":2}}],["header",{"2":{"43":2,"172":2,"590":4,"614":4}}],["healthcheck",{"2":{"61":2}}],["hover",{"2":{"465":1}}],["hobby",{"2":{"318":6,"319":10}}],["hour",{"2":{"268":2}}],["hosts",{"2":{"450":4}}],["hostname",{"2":{"235":4}}],["hostlistener",{"2":{"125":6}}],["hostview",{"2":{"113":4}}],["host选择是是把宿主元素作为目标的唯一方式",{"2":{"98":1}}],["host主机模式",{"2":{"62":2}}],["host",{"0":{"592":1},"1":{"593":1,"594":1},"2":{"34":2,"62":2,"98":2,"99":2,"235":2,"590":2,"592":2}}],["home",{"2":{"21":2,"61":4,"150":2,"151":4,"152":4,"153":4,"427":2}}],["h1",{"2":{"21":12,"22":8,"84":4,"137":4,"143":4,"346":14,"349":14}}],["htm",{"2":{"350":2}}],["htmlevents",{"2":{"584":2}}],["htmlelement",{"2":{"113":2}}],["htmlcanvaselement",{"2":{"551":6}}],["htmlwebpackplugin",{"2":{"418":4,"548":1}}],["html=",{"2":{"347":2}}],["htmlangular",{"2":{"129":1}}],["html标签",{"2":{"99":1}}],["html",{"0":{"454":1,"456":1,"566":1},"2":{"20":2,"21":6,"22":14,"78":1,"85":2,"86":1,"87":1,"88":1,"102":4,"103":2,"104":4,"105":6,"106":4,"107":1,"109":2,"113":2,"114":6,"116":8,"117":1,"118":1,"119":1,"121":2,"122":1,"124":1,"128":3,"133":1,"150":1,"151":1,"152":1,"153":1,"168":1,"170":1,"177":1,"178":1,"303":5,"347":2,"418":6,"444":1,"445":1,"449":3,"455":2,"456":6,"478":1,"482":1,"483":1,"528":1,"548":1,"551":3,"573":2,"586":3,"587":2,"609":1}}],["http缓存",{"0":{"471":1}}],["http与https区别",{"0":{"469":1}}],["https",{"2":{"66":2,"229":1,"396":2,"469":1}}],["http",{"0":{"40":1,"452":1,"454":1},"1":{"453":1},"2":{"15":6,"20":7,"21":6,"22":12,"40":1,"42":2,"43":2,"45":2,"46":5,"51":2,"62":2,"243":8,"449":3,"452":1,"454":1,"469":1,"573":1,"589":4}}],["vh",{"2":{"583":2}}],["vp",{"2":{"603":2}}],["vpnavbarhamburger",{"2":{"603":2}}],["vpn",{"2":{"578":2}}],["vpe节点",{"2":{"577":2}}],["vpe",{"2":{"577":2,"578":2}}],["vnode是一个纯",{"2":{"560":1}}],["vnode",{"0":{"560":1},"2":{"560":2}}],["vm",{"2":{"553":1}}],["vw",{"2":{"488":1,"583":2}}],["v1",{"2":{"396":2}}],["vendor",{"2":{"571":2}}],["ve",{"2":{"235":1}}],["verify",{"2":{"230":2}}],["vertical",{"2":{"176":2,"177":2,"577":2,"611":2}}],["version",{"2":{"51":2,"396":2}}],["vscode",{"2":{"357":2}}],["vs",{"0":{"230":1}}],["vdom",{"2":{"137":4}}],["v8及以前",{"2":{"113":1}}],["v9和v10",{"2":{"113":1}}],["void\\t",{"2":{"400":2}}],["void",{"2":{"103":4,"104":4,"105":4,"106":4,"108":2,"109":16,"113":6,"114":2,"116":4,"121":2,"126":2,"411":2,"427":2}}],["volume",{"2":{"61":2}}],["visible",{"2":{"609":2}}],["visible=",{"2":{"609":2}}],["video",{"2":{"483":1}}],["vite项目",{"0":{"564":1}}],["vite",{"2":{"535":1,"564":4,"589":2,"599":2,"602":4}}],["vitepress也不生效",{"2":{"602":1}}],["vitepress添加本地搜索功能",{"0":{"600":1},"1":{"601":1,"602":1,"603":1}}],["vitepress踩坑记录",{"0":{"591":1},"1":{"592":1,"593":1,"594":1,"595":1,"596":1,"597":1,"598":1,"599":1,"600":1,"601":1,"602":1,"603":1}}],["vitepress",{"2":{"395":2,"599":8,"601":2,"602":3}}],["vite底层原理学习",{"0":{"148":1},"1":{"149":1}}],["viewregister",{"2":{"577":4,"578":2}}],["view",{"2":{"553":1}}],["viewer",{"2":{"211":10}}],["viewcontainer",{"2":{"126":8}}],["viewcontainerref",{"2":{"126":4}}],["viewchild获取子组件一样",{"2":{"113":2}}],["viewchildren批量获取元素和组件",{"2":{"104":4}}],["viewchildren",{"0":{"104":1},"2":{"104":6}}],["viewchild",{"0":{"103":1},"2":{"103":8,"104":2,"118":2,"121":4}}],["viewtomodelupdate",{"2":{"118":2}}],["viewmodel",{"2":{"118":2,"553":1}}],["vi",{"2":{"75":2}}],["vim",{"2":{"55":4}}],["v",{"2":{"72":2,"211":4,"324":18,"347":2,"547":2,"553":1,"610":4,"611":2}}],["v2",{"2":{"66":2}}],["val2",{"2":{"318":4}}],["val1",{"2":{"318":4}}],["val",{"2":{"114":4,"153":2,"299":12,"316":6,"322":6,"323":4,"324":4,"380":4,"382":4,"509":6,"510":1,"523":2,"536":14,"610":2}}],["val=",{"2":{"114":4,"150":2,"322":2}}],["valueof",{"0":{"533":1},"2":{"509":1,"512":3,"530":1,"533":6}}],["value=",{"2":{"123":8}}],["values",{"2":{"36":2,"265":2,"357":2}}],["value",{"2":{"13":4,"36":4,"96":6,"107":8,"108":2,"114":8,"117":4,"118":8,"130":6,"146":4,"157":10,"158":2,"265":13,"296":14,"298":8,"300":56,"303":8,"304":8,"305":4,"306":4,"307":20,"308":28,"309":4,"310":28,"311":22,"312":8,"313":4,"314":4,"315":54,"334":12,"335":4,"357":2,"364":4,"365":10,"523":4,"525":10,"574":10,"578":6,"589":2,"610":10,"614":4}}],["var",{"0":{"514":1},"1":{"515":1,"516":1},"2":{"61":4,"130":2,"282":4,"288":3,"300":8,"303":2,"307":1,"363":1,"364":3,"365":4,"370":4,"384":2,"389":1,"495":2,"498":2,"512":8,"514":1,"524":2,"574":2,"584":4,"602":2,"603":2}}],["vue项目踩坑一",{"0":{"608":1},"1":{"609":1,"610":1,"611":1,"612":1,"613":1,"614":1,"615":1}}],["vuepress踩坑记录",{"0":{"604":1},"1":{"605":1,"606":1,"607":1}}],["vueproject",{"2":{"599":2}}],["vuerouter",{"2":{"572":4}}],["vuerouter的base属性是指应用的基路径",{"2":{"572":1}}],["vuerouter的",{"0":{"572":1}}],["vue3",{"0":{"561":1}}],["vue声明周期",{"0":{"555":1},"1":{"556":1}}],["vue中循环注册组件",{"0":{"375":1}}],["vue中的key有什么作用",{"2":{"147":2}}],["vue模板解析",{"2":{"338":1}}],["vuex",{"2":{"156":2,"157":2,"426":2}}],["vue",{"0":{"15":1,"45":1,"158":1,"563":1,"573":1},"2":{"15":1,"45":1,"46":2,"278":1,"335":1,"357":1,"375":1,"427":2,"429":1,"432":1,"433":4,"554":1,"560":1,"563":6,"573":9,"574":2,"610":1,"613":2,"614":3}}],["发起",{"0":{"452":1},"1":{"453":1},"2":{"449":1}}],["发生继承时",{"2":{"410":1}}],["发生了什么",{"2":{"139":2,"140":1}}],["发现代码有的有点小问题",{"2":{"213":1}}],["发现组件是使用类定义的",{"2":{"140":1}}],["发现组件是使用函数定义的",{"2":{"139":2}}],["发布和拉取",{"2":{"55":2}}],["发送请求",{"2":{"494":2}}],["发送网络请求",{"2":{"147":4}}],["发送并保存在客户端",{"2":{"43":1}}],["发送合并切片请求",{"2":{"14":1}}],["发请求检查文件是否已传过",{"2":{"14":1}}],["秒传成功",{"2":{"14":1}}],["b路由组件",{"2":{"612":2}}],["bg",{"2":{"578":2,"603":2,"614":2}}],["bfs",{"0":{"544":1},"2":{"544":9}}],["bfc",{"2":{"482":2}}],["bfa",{"2":{"99":2}}],["blur",{"2":{"610":2}}],["blur=",{"2":{"610":2}}],["blue",{"2":{"399":2,"481":2,"491":10}}],["block",{"2":{"113":2,"121":2,"189":2,"190":4,"490":2,"551":2}}],["blobarraybuffer",{"2":{"330":6,"332":2}}],["blob与",{"0":{"329":1}}],["blob",{"2":{"15":6,"229":1,"329":4,"330":6,"335":10,"336":2}}],["bc41wb16",{"2":{"357":2}}],["bset",{"2":{"324":4}}],["bst",{"2":{"300":16}}],["b表达式",{"2":{"258":1}}],["bruce",{"2":{"385":4}}],["breg",{"2":{"349":6}}],["breakpoint",{"2":{"489":1}}],["break立即循环停止",{"2":{"260":1}}],["break与continue💔终止离它最近的循环",{"2":{"260":1}}],["break",{"2":{"259":2,"316":2}}],["branches",{"2":{"396":2}}],["branch",{"2":{"206":6,"211":4,"217":4,"396":2}}],["bridge",{"2":{"62":2}}],["bbb",{"2":{"195":2}}],["be",{"2":{"295":2,"551":2,"592":1}}],["beforeunmount",{"2":{"615":2}}],["beforeupdate",{"2":{"555":2}}],["beforedestroy",{"2":{"577":2}}],["beforedestory",{"2":{"555":2}}],["beforemount",{"2":{"555":2,"556":6,"559":2}}],["beforecreate",{"0":{"557":1},"2":{"555":2,"556":6,"559":2}}],["before在",{"2":{"459":1}}],["before",{"2":{"179":2,"190":2,"195":4,"197":2,"609":2}}],["bestbydate",{"2":{"135":2}}],["b=",{"2":{"145":2,"325":2}}],["b=10",{"2":{"61":2}}],["bai",{"2":{"532":6}}],["baidulet",{"2":{"350":1}}],["baidu88baidu",{"2":{"350":2}}],["baidu",{"2":{"341":2,"346":8,"347":12,"349":12,"350":5,"532":10}}],["backlist",{"2":{"599":10}}],["back3",{"2":{"578":4}}],["back2",{"2":{"578":4}}],["back1",{"2":{"578":4}}],["backdrop",{"2":{"479":1}}],["backgroundcolor",{"2":{"125":2}}],["background",{"2":{"99":3,"156":2,"177":4,"178":2,"179":2,"184":4,"185":1,"186":14,"189":4,"190":2,"195":10,"198":8,"199":6,"203":2,"478":1,"481":2,"491":10,"551":2,"603":4}}],["bark",{"2":{"409":4,"410":4,"411":2}}],["banana",{"2":{"364":4}}],["babel在webpack中的加载器",{"2":{"422":1}}],["babel的预定义环境",{"2":{"422":1}}],["babel的核心工具",{"2":{"422":1}}],["babel作用",{"2":{"422":1}}],["babel语法降级",{"2":{"149":1}}],["babel",{"0":{"422":1},"2":{"139":4,"418":6,"422":6,"423":4,"570":3}}],["bashnpm",{"2":{"417":1,"601":1}}],["bashnginx",{"2":{"73":1}}],["bashhost",{"2":{"235":1}}],["bashgit",{"2":{"234":1}}],["bashget",{"2":{"223":1}}],["bashthe",{"2":{"230":1}}],["bashcode",{"2":{"228":1}}],["bashcurl",{"2":{"66":1}}],["bash$profile$profile",{"2":{"227":1}}],["bashoh",{"2":{"224":1,"227":1}}],["bashwinget",{"2":{"222":1}}],["baship",{"2":{"75":1}}],["bash",{"2":{"55":3,"56":6,"59":2,"61":2,"63":2,"64":1,"234":1}}],["bashagt",{"2":{"55":1}}],["bashdocker",{"2":{"55":1,"56":1,"57":1,"58":1,"59":1,"62":1,"63":1,"64":1}}],["bashset",{"2":{"234":1}}],["bashssh",{"2":{"232":1,"234":2,"235":1}}],["bashsystemctl",{"2":{"54":1}}],["bashsudo",{"2":{"51":1}}],["base属性可以通过以下方式设置",{"2":{"572":1}}],["baseurl不可少",{"2":{"433":2}}],["baseurl",{"2":{"433":2,"440":4}}],["base64",{"2":{"336":1}}],["baseschema",{"2":{"13":8}}],["base",{"0":{"572":1},"2":{"13":5,"414":2,"440":2,"572":4,"573":4}}],["btns",{"2":{"536":8}}],["btncls3",{"2":{"90":10}}],["btncls2",{"2":{"90":10}}],["btncls",{"2":{"90":10}}],["btn",{"2":{"89":24,"90":12,"357":2,"536":2}}],["bubbles",{"2":{"584":2}}],["bubblesort",{"2":{"287":2}}],["bubble",{"2":{"577":2}}],["bundle",{"2":{"418":2}}],["bunits",{"2":{"302":4}}],["but",{"2":{"235":1}}],["buttonlabel",{"2":{"602":2}}],["button",{"2":{"15":4,"46":4,"86":4,"89":36,"90":36,"93":8,"96":4,"108":4,"116":16,"121":4,"126":4,"130":8,"189":4,"357":4,"491":30,"603":6}}],["buildlocal",{"2":{"573":4}}],["build对代码进行编译",{"2":{"421":1}}],["build",{"2":{"61":6,"395":2,"396":12,"420":2,"573":8}}],["b",{"0":{"324":1,"328":1},"2":{"17":4,"146":3,"147":2,"168":10,"170":10,"173":4,"243":4,"253":2,"256":4,"258":3,"264":6,"284":8,"287":16,"297":8,"316":4,"319":8,"321":2,"322":2,"324":16,"388":13,"389":4,"399":12,"400":6,"402":4,"432":2,"524":4,"539":8}}],["big",{"2":{"513":1}}],["bigchinese",{"2":{"302":4}}],["bigint转为数字",{"2":{"509":1}}],["bigint",{"2":{"261":2,"414":2,"506":1}}],["bin",{"2":{"55":2,"56":6,"59":2,"61":4,"63":2,"66":2,"395":2,"563":3,"564":3}}],["bind修改它的this",{"2":{"262":1}}],["bind可以为新函数绑定参数",{"2":{"262":1}}],["bind可以为新函数绑定this",{"2":{"262":1}}],["bind",{"2":{"13":2,"86":2,"262":3,"303":4,"304":4,"315":4,"574":4}}],["bio",{"2":{"13":2}}],["bower",{"2":{"414":2}}],["bob",{"2":{"385":4}}],["bottom",{"2":{"179":2,"184":2,"189":2,"190":4,"195":10,"474":2,"479":1,"490":4}}],["boxs",{"2":{"104":14}}],["box",{"2":{"103":10,"105":20,"106":28,"108":4,"164":2,"166":2,"167":4,"168":6,"170":4,"176":4,"183":1,"184":2,"185":2,"190":6,"191":1,"195":7,"198":4,"199":2,"203":2,"474":2,"475":4}}],["border",{"2":{"91":4,"92":6,"98":2,"168":2,"170":2,"177":2,"185":2,"188":6,"189":2,"190":8,"195":8,"457":1,"475":3,"481":2,"482":4,"491":10,"603":10,"609":2}}],["boost",{"2":{"107":2}}],["bootstrap",{"0":{"82":1},"2":{"78":1,"82":4}}],["boolean值",{"2":{"428":1,"434":1,"435":1,"436":1,"437":1}}],["boolean类型",{"2":{"426":1,"427":1}}],["boolean\\t",{"2":{"122":8}}],["boolean",{"2":{"7":4,"108":2,"126":2,"261":2,"318":2,"400":2,"506":2,"519":4}}],["bodyparser",{"2":{"43":4}}],["body",{"2":{"9":2,"10":2,"11":8,"12":2,"13":2,"30":6,"42":6,"43":6,"113":2,"177":4,"202":1,"303":4,"479":1,"541":4,"574":4,"589":2}}],["模糊电话后四位",{"0":{"353":1}}],["模糊查询",{"2":{"4":1}}],["模式修正符号i",{"0":{"345":1}}],["模版中还可以写些简单的逻辑",{"2":{"84":1}}],["模板变量可以通过一条或多条管道格式化数据",{"2":{"132":1}}],["模板引用变量",{"0":{"130":1}}],["模板元素",{"0":{"127":1},"1":{"128":1,"129":1,"130":1}}],["模板的引用",{"2":{"121":2}}],["模板中的dom事件触发就会进行变更检测",{"2":{"109":1}}],["模板来源",{"0":{"85":1}}],["模板表达式遵循原则",{"2":{"84":1}}],["模板表达式",{"0":{"84":1}}],["模板基础语法",{"0":{"83":1},"1":{"84":1,"85":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1}}],["模块名到基于",{"2":{"440":2}}],["模块名或路径映射的列表",{"2":{"433":1}}],["模块解析选项",{"2":{"440":2}}],["模块实际位置",{"2":{"433":4}}],["模块想要正常工作",{"2":{"80":2}}],["模块中使用的组件必须先在declarations",{"2":{"79":2}}],["模块多次",{"2":{"26":1}}],["模块加载机制",{"0":{"26":1}}],["模块共享",{"0":{"25":1}}],["模块分为",{"2":{"23":1}}],["模块化开发支持",{"2":{"149":1}}],["模块化",{"0":{"23":1,"535":1},"1":{"24":1,"25":1}}],["模块",{"0":{"27":1,"34":1},"1":{"28":1,"29":1},"2":{"20":1,"34":1}}],["模型演变而来",{"2":{"553":1}}],["模型",{"0":{"13":1}}],["获取和解析命令行参数",{"2":{"563":1}}],["获取本次",{"2":{"525":2}}],["获取数据",{"2":{"523":2}}],["获取数量",{"2":{"266":2}}],["获取原始值",{"2":{"509":1}}],["获取原来的文件名",{"2":{"46":2}}],["获取布局属性时",{"2":{"465":1}}],["获取目录结构",{"0":{"357":1}}],["获取缓存中对应key的值",{"2":{"296":2}}],["获取map的所有的value",{"2":{"265":1}}],["获取map的所有的valueconst",{"2":{"265":1}}],["获取map的所有的key",{"2":{"265":2}}],["获取map中键值对的数量",{"2":{"265":2}}],["获取render之前的dom状态",{"2":{"147":1}}],["获取到powershell配置文件绝对路径",{"2":{"227":1}}],["获取到",{"2":{"121":2}}],["获取",{"2":{"118":2}}],["获取不到最新输入属性值",{"2":{"109":2}}],["获取全部投影组件",{"2":{"106":2}}],["获取所有组件需开启",{"2":{"106":1}}],["获取组件的变量elseblocks",{"2":{"121":2}}],["获取组件实例",{"2":{"113":2}}],["获取组件",{"2":{"105":2}}],["获取投影中的dom元素",{"2":{"105":3}}],["获取子组件实例方式二",{"2":{"103":2}}],["获取子组件方式一",{"2":{"103":2}}],["获取dom",{"2":{"103":2,"125":2}}],["获取用户信息成功",{"2":{"43":2}}],["获取用户信息",{"2":{"43":2}}],["获取用户姓名的接口",{"2":{"42":2}}],["获取文件前缀",{"2":{"46":2}}],["获取文件扩展名",{"2":{"17":1}}],["获取文章列表",{"2":{"12":2}}],["获取一个文章",{"2":{"12":2}}],["文本溢出隐藏处理后对不齐问题",{"0":{"611":1}}],["文本行斑马线",{"0":{"198":1}}],["文末也会附上笔者整理的所有tsconfig",{"2":{"425":1}}],["文件下载好",{"2":{"456":1}}],["文件还没有下载解析好",{"2":{"456":1}}],["文件和外部的js",{"2":{"456":1}}],["文件而不是源文件的位置",{"2":{"440":2}}],["文件大小",{"2":{"357":2}}],["文件操作",{"0":{"334":1}}],["文件名就是config",{"2":{"235":1}}],["文件中也没有找到对应的条目",{"2":{"450":1}}],["文件中的错误",{"2":{"440":2}}],["文件中",{"2":{"221":1,"563":1,"564":1}}],["文件夹名称",{"2":{"208":4}}],["文件",{"2":{"208":4,"440":8,"450":2,"456":1,"497":1,"548":1}}],["文章模型",{"2":{"13":2}}],["文章查询列表成功",{"2":{"12":2}}],["文章查询成功",{"2":{"12":2}}],["文章不存在",{"2":{"12":2}}],["文章更新成功",{"2":{"11":2}}],["文章删除成功",{"2":{"10":2}}],["文档相关操作",{"0":{"3":1},"1":{"4":1,"5":1,"6":1,"7":1}}],["easing",{"2":{"578":10}}],["easecubic",{"2":{"578":10}}],["ease",{"2":{"179":2}}],["echart文档参考",{"2":{"585":1}}],["echarts问题总结",{"0":{"582":1},"1":{"583":1,"584":1,"585":1}}],["echo",{"2":{"420":2}}],["ecmascript",{"2":{"388":1,"440":2}}],["equaltype",{"2":{"318":4}}],["edit",{"2":{"213":3,"214":2,"610":4}}],["edb21d",{"2":{"195":2}}],["edges",{"2":{"577":4}}],["edge",{"2":{"194":1,"577":2}}],["es7",{"2":{"414":2}}],["es2020",{"2":{"414":18}}],["es2019",{"2":{"414":12}}],["es2018",{"2":{"414":14}}],["es2017",{"2":{"414":14,"429":1,"440":2}}],["es2016",{"2":{"414":6,"429":1,"440":2}}],["es2015",{"2":{"414":28,"419":4,"429":1,"430":1,"440":4}}],["es6module都支持",{"2":{"535":1}}],["es6",{"0":{"502":1},"2":{"414":6,"429":1,"430":2,"431":2,"492":1,"549":2}}],["es6的flat方法实现",{"2":{"282":2}}],["es5",{"2":{"414":4,"429":1,"431":1,"440":4}}],["es3",{"2":{"414":2,"429":2,"440":2}}],["eslint的rule中也有该条",{"2":{"435":1}}],["eslintrc",{"2":{"357":2}}],["eslint代码检查",{"2":{"149":1}}],["esnext",{"2":{"414":14,"429":3,"430":1,"431":1,"440":4}}],["esn",{"2":{"158":4}}],["es",{"2":{"149":1}}],["eval",{"2":{"539":2}}],["evaluated",{"2":{"426":2}}],["every",{"2":{"318":2,"328":2,"348":4}}],["evenly",{"2":{"167":4}}],["even",{"2":{"122":8}}],["eventhandle",{"2":{"577":2}}],["eventb",{"2":{"293":6}}],["eventa",{"2":{"293":6}}],["eventname",{"2":{"293":14}}],["eventemitter",{"2":{"96":4,"113":4,"116":8,"125":4,"293":14}}],["event",{"2":{"93":4,"125":2,"146":12,"528":4,"551":4,"584":8}}],["ev=",{"2":{"122":2}}],["ev",{"2":{"122":4,"584":4}}],["empty",{"2":{"592":1}}],["employee",{"2":{"406":6}}],["em",{"2":{"458":1}}],["embeddedviewref",{"2":{"113":4}}],["emulated",{"2":{"101":1}}],["emitdecoratormetadata",{"2":{"440":2}}],["emit",{"2":{"96":2,"113":2,"116":8,"125":2,"293":6}}],["email",{"2":{"13":2}}],["ei",{"2":{"73":2}}],["etc",{"2":{"61":10,"75":2,"450":1}}],["ef",{"2":{"51":2,"72":1}}],["enum\\t",{"2":{"400":2}}],["english",{"2":{"384":2}}],["en",{"2":{"268":2}}],["entries",{"2":{"266":2,"599":2,"615":4}}],["entry",{"2":{"250":6,"265":2,"357":8,"418":2}}],["entrycomponents可能被删除",{"2":{"113":1}}],["entrypoint",{"2":{"61":4}}],["enteries",{"2":{"250":4}}],["enter",{"2":{"108":2}}],["ens160",{"2":{"75":2}}],["environment",{"2":{"418":2}}],["env",{"2":{"61":2,"395":2,"396":2,"418":2,"422":2,"423":2,"570":4,"573":8}}],["enable",{"2":{"54":2}}],["enctype=",{"2":{"46":2}}],["endswith",{"2":{"530":1}}],["ending",{"2":{"524":2}}],["enddate",{"2":{"294":4}}],["end",{"2":{"15":8,"20":2,"21":2,"22":8,"168":4,"172":4,"173":6,"174":4,"294":4}}],["e",{"2":{"15":4,"45":4,"214":2,"249":2,"331":16,"333":8,"335":4,"395":2,"400":13,"495":20,"551":4,"577":2,"610":4,"615":6}}],["example",{"2":{"572":1,"573":1}}],["exclude排除那些不需要编译的文件或文件夹",{"2":{"439":1}}],["exclude",{"2":{"357":4,"414":4,"418":2,"423":2,"439":2,"440":2,"599":4}}],["exe",{"2":{"231":2,"420":2}}],["exe的路径",{"2":{"231":2}}],["execcommand",{"2":{"574":4}}],["exec输出结果中",{"2":{"346":2}}],["execute",{"2":{"551":2}}],["executor",{"2":{"303":4,"304":4,"315":4}}],["executable",{"2":{"230":2}}],["exec",{"2":{"56":2}}],["exit退出不会停止容器",{"2":{"56":2}}],["exit",{"2":{"56":2,"420":2}}],["exists",{"2":{"234":2}}],["existssync",{"2":{"46":2,"599":2}}],["exist",{"2":{"15":2,"586":2}}],["extensions",{"2":{"418":2}}],["extend适用于继承现有样式并生成新的选择器",{"2":{"491":1}}],["extend的选择器的样式",{"2":{"491":1}}],["extend的区别",{"0":{"491":1}}],["extend则会生成一个新的选择器",{"2":{"491":1}}],["extend",{"2":{"427":2,"491":8}}],["extends",{"2":{"140":2,"143":2,"144":2,"145":2,"220":2,"271":2,"405":2,"406":6,"409":2,"410":2,"411":2,"414":4,"424":2,"440":2,"502":2}}],["extended",{"2":{"30":2,"42":2,"43":2}}],["extname",{"2":{"17":2,"46":2}}],["expires=xxx",{"2":{"523":2}}],["expires",{"2":{"471":1}}],["expiresin",{"2":{"43":2}}],["experimentaldecorators",{"0":{"426":1},"2":{"440":2}}],["exponent",{"2":{"107":8}}],["expose",{"2":{"61":2}}],["exported",{"2":{"551":2}}],["export",{"2":{"59":2,"84":2,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":4,"96":4,"103":2,"104":2,"105":2,"106":2,"107":2,"108":4,"109":2,"113":6,"114":2,"116":8,"119":2,"121":6,"122":2,"123":2,"125":2,"126":6,"130":4,"151":2,"152":2,"153":2,"156":1,"157":2,"427":1,"551":1,"574":2,"578":8,"585":1,"589":1,"602":2,"610":2}}],["exports中",{"2":{"418":2}}],["exports=",{"2":{"25":2}}],["exports将模块内部成员共享",{"2":{"24":1}}],["exports模式是空对象",{"2":{"24":1}}],["exports",{"2":{"9":1,"10":1,"11":1,"12":4,"13":8,"25":6,"30":2,"220":2,"418":2,"570":2,"573":2}}],["expressionoh",{"2":{"227":1}}],["expression",{"2":{"224":2,"227":1}}],["expressjwt",{"2":{"43":4}}],["express",{"0":{"27":1,"28":1,"29":1,"46":1},"1":{"28":1,"29":1},"2":{"28":6,"29":12,"30":14,"42":16,"43":15,"46":8}}],["expports指向的对象",{"2":{"25":1}}],["expports为准",{"2":{"25":1}}],["elet",{"2":{"400":1}}],["ele",{"2":{"375":2,"541":18}}],["element",{"0":{"588":1},"2":{"364":4,"528":1,"574":2,"588":1}}],["elementref",{"2":{"103":4,"105":8,"125":4}}],["ellipsislength",{"2":{"578":6}}],["ellipsis",{"2":{"176":4,"578":6,"611":2}}],["elseblocks",{"2":{"121":6}}],["elseblock",{"2":{"121":10}}],["else",{"0":{"244":1},"1":{"245":1,"246":1,"247":1},"2":{"15":2,"21":2,"22":4,"121":6,"126":2,"159":2,"245":6,"246":2,"247":2,"259":4,"279":10,"282":2,"292":6,"295":2,"296":2,"300":20,"302":2,"309":4,"310":6,"311":2,"312":2,"315":4,"316":2,"357":2,"385":2,"525":2,"541":4,"577":4,"578":16,"584":2,"599":4,"610":6,"614":2}}],["el",{"2":{"15":8,"125":4,"374":4,"574":30,"609":16,"610":12,"611":4}}],["err",{"0":{"592":1},"1":{"593":1,"594":1},"2":{"16":12,"18":6,"22":8,"34":6,"35":6,"36":12,"37":12,"38":12,"43":4,"45":6,"295":16,"493":4,"494":4,"592":1}}],["errs",{"2":{"10":2,"11":2,"12":8}}],["error",{"2":{"9":4,"10":4,"11":4,"12":8,"13":4,"15":2,"159":2,"217":2,"234":2,"239":11,"242":4,"288":2,"295":6,"302":2,"306":8,"308":16,"309":8,"310":20,"311":4,"315":6,"400":2,"420":2,"428":2,"434":2,"493":4,"506":1,"551":4,"610":4}}],["nitro",{"2":{"589":2,"590":1}}],["niltor",{"2":{"229":1}}],["nreversed",{"2":{"298":2}}],["n5",{"2":{"298":4}}],["n4",{"2":{"298":6}}],["n3",{"2":{"298":6}}],["n2",{"2":{"298":6,"399":2}}],["n1+n2",{"2":{"399":2}}],["n1",{"2":{"298":6,"399":2}}],["npm",{"0":{"562":1},"1":{"563":1,"564":1},"2":{"221":2,"395":2,"416":1,"418":10,"422":1,"563":2,"564":1,"570":1}}],["n",{"2":{"208":2,"281":18,"285":14,"301":4,"302":6,"347":4,"362":4,"373":4,"509":1,"510":2,"543":2,"544":2}}],["nav",{"2":{"586":4}}],["native",{"2":{"440":2}}],["nativeelement",{"2":{"103":4,"125":2}}],["nan不和任何值相等",{"2":{"257":2}}],["nan",{"2":{"251":2,"255":2,"322":10,"323":2,"509":5,"511":1,"512":4}}],["namenum",{"2":{"385":4}}],["names",{"2":{"385":4}}],["name就可以调用",{"2":{"272":2}}],["namearr",{"2":{"157":4}}],["name===",{"2":{"245":6}}],["name=",{"2":{"29":4,"37":2,"46":2,"56":4,"118":2,"123":8,"144":6,"146":4}}],["name",{"2":{"2":2,"4":18,"5":20,"6":2,"13":2,"15":18,"25":12,"29":8,"30":2,"35":4,"36":4,"37":4,"43":2,"62":4,"63":2,"64":8,"107":2,"108":30,"118":10,"122":12,"133":2,"144":14,"157":10,"158":4,"159":6,"230":4,"231":2,"234":1,"245":8,"246":6,"247":2,"265":4,"269":10,"270":30,"271":10,"272":2,"318":6,"319":10,"325":18,"357":16,"396":14,"399":12,"400":4,"401":2,"402":2,"404":10,"405":16,"406":60,"407":24,"409":10,"410":10,"428":8,"450":1,"498":8,"502":4,"503":4,"504":4,"527":2,"536":4,"571":4,"578":34,"580":2,"609":4,"610":12}}],["ngswitchdefault",{"2":{"123":4}}],["ngswitchcase=",{"2":{"123":12}}],["ngswitchcase为结构型指令",{"2":{"123":1}}],["ngswitch",{"0":{"123":1},"2":{"123":6}}],["ngstyle只接收对象",{"2":{"92":2}}],["ngstyle",{"2":{"92":6}}],["ngfortrackby",{"2":{"122":2}}],["ngfor",{"2":{"122":2}}],["ngfor展开写法",{"2":{"122":1}}],["ngforof",{"2":{"122":4}}],["ngfor局部变量",{"2":{"122":1}}],["ngfor指令",{"0":{"122":1}}],["ngfor=",{"2":{"108":2,"122":2}}],["ngiterable",{"2":{"122":2}}],["ngifthen",{"2":{"121":1}}],["ngifelese",{"2":{"121":1}}],["ngif",{"2":{"121":3}}],["ngif=",{"2":{"121":12}}],["ngif指令",{"0":{"121":1}}],["nginx安装",{"0":{"69":1},"1":{"70":1,"71":1,"72":1}}],["nginx",{"0":{"613":1},"2":{"61":24,"70":2,"72":6,"73":4,"573":2,"589":2,"590":3}}],["ngmoel",{"2":{"117":4}}],["ngmodel拓展",{"2":{"118":1}}],["ngmodeloptions",{"2":{"118":6}}],["ngmodelchange",{"2":{"117":2}}],["ngmodel",{"2":{"107":4,"117":2,"118":21,"123":8}}],["ngmodule装饰器中",{"2":{"80":2}}],["ngmodule元数据",{"0":{"78":1}}],["ngmodule所装饰的类被称为angular",{"2":{"77":1}}],["ngmodule",{"0":{"77":1},"1":{"78":1,"79":1,"80":1,"81":1,"82":1}}],["ngtemplateoutlet=",{"2":{"114":4}}],["ngtemplateoutletcontext",{"2":{"114":4}}],["ngtemplateoutlet",{"2":{"114":6}}],["ngtemplateoutlet是一个结构型指令",{"2":{"114":1}}],["ngtemplateoutlet指令",{"0":{"114":1}}],["ngafterviewchecked",{"2":{"109":6}}],["ngafterviewinit",{"2":{"103":8,"104":2,"105":2,"106":2,"109":5}}],["ngaftercontentchecked",{"2":{"109":6}}],["ngaftercontentinit",{"2":{"109":5}}],["ngdocheck",{"2":{"109":6}}],["ngondestroy",{"2":{"109":5}}],["ngonchanges",{"2":{"109":3,"126":2}}],["ngoninit",{"2":{"103":10,"104":2,"105":2,"106":2,"108":2,"109":5,"113":4,"114":2,"116":4,"121":4}}],["ng",{"0":{"128":1,"129":1},"2":{"102":12,"105":4,"114":38,"121":20,"122":4,"123":16,"128":5,"129":4}}],["ngclass",{"2":{"90":6}}],["nofallthroughcasesinswitch",{"2":{"440":2}}],["nounusedparameters",{"0":{"436":1},"2":{"440":2}}],["nounusedlocals",{"0":{"435":1},"2":{"440":2}}],["noimplicitreturns",{"2":{"440":2}}],["noimplicitthis",{"2":{"414":2,"434":1,"440":2}}],["noimplicitany",{"0":{"428":1},"2":{"414":2,"434":1,"440":2}}],["noemitonerror",{"2":{"414":2}}],["noemit",{"2":{"414":2,"440":2}}],["nologo",{"2":{"231":4}}],["nologo为隐藏提示语",{"2":{"231":1}}],["non",{"2":{"134":1}}],["none",{"2":{"62":2,"101":1,"177":8,"189":4,"197":2,"414":2,"430":1,"459":1,"479":1,"491":10,"603":2,"605":2}}],["no",{"2":{"134":1,"195":2,"199":2,"213":3,"234":1,"420":2,"551":2,"578":2}}],["normal",{"2":{"107":2}}],["notification",{"2":{"574":6}}],["note",{"2":{"195":2}}],["not",{"2":{"21":2,"22":4,"197":1,"230":2,"234":3,"235":1,"288":2,"519":2,"551":2,"586":2}}],["nodesfilter",{"2":{"577":2}}],["nodes",{"2":{"543":24,"544":22,"577":4}}],["node模块解析方式",{"2":{"432":2}}],["node",{"0":{"23":1,"33":1,"44":1},"1":{"24":1,"25":1,"34":1,"35":1,"36":1,"37":1,"38":1,"45":1,"46":1},"2":{"16":2,"25":1,"298":12,"300":36,"357":2,"396":7,"414":2,"418":2,"423":2,"432":1,"439":2,"440":8,"535":1,"543":22,"544":28,"549":1,"563":3,"564":3,"570":2,"571":4,"573":2,"577":6,"613":2}}],["node大文件上传",{"0":{"14":1},"1":{"15":1}}],["nowrap",{"2":{"176":2,"611":2}}],["now",{"2":{"13":4,"46":2,"108":4,"519":4,"520":8}}],["nuxt",{"0":{"590":1}}],["num2",{"2":{"408":4}}],["num1",{"2":{"408":4}}],["nums",{"2":{"362":2,"382":6}}],["numstr",{"2":{"302":6}}],["nums2",{"2":{"292":20}}],["nums1",{"2":{"292":20}}],["numeric",{"2":{"268":2}}],["num",{"2":{"263":4,"264":4,"302":28,"405":12}}],["number类型包含了null和undefined类型",{"2":{"434":2}}],["number|string",{"2":{"402":2}}],["numbertochinese",{"2":{"302":6}}],["number\\t",{"2":{"122":4}}],["number",{"2":{"12":4,"13":2,"15":2,"84":2,"107":6,"116":4,"130":4,"144":6,"158":4,"318":8,"319":10,"399":16,"400":6,"402":2,"404":4,"405":10,"406":18,"408":4,"409":4,"410":4,"412":2,"434":2,"506":2,"533":2}}],["null是",{"2":{"507":1}}],["null和undefined获得了它们自己各自的类型null和undefined",{"2":{"434":1}}],["null和undefined进行相等比较会返回true",{"2":{"257":2}}],["null检查模式",{"2":{"434":1}}],["null",{"2":{"12":2,"13":6,"46":4,"113":2,"121":4,"126":6,"134":1,"231":2,"251":2,"257":4,"261":2,"274":1,"298":8,"299":4,"300":30,"303":2,"304":2,"315":2,"318":15,"319":2,"334":2,"375":2,"399":2,"434":2,"440":2,"499":2,"500":1,"506":1,"507":3,"509":3,"511":1,"512":5,"519":4,"520":4,"527":2,"533":1,"544":2,"551":2,"577":2,"599":2}}],["nex",{"2":{"524":1}}],["next",{"2":{"9":4,"10":2,"11":2,"12":4,"29":22,"43":2,"46":2,"156":2,"296":2,"298":24,"524":4,"525":6}}],["netbios",{"2":{"450":1}}],["network",{"2":{"62":16,"63":2,"64":8,"75":4}}],["never\\t",{"2":{"400":2}}],["nerd",{"2":{"230":1,"231":2}}],["new操作符会创建一个新对象",{"2":{"498":1}}],["newnums",{"2":{"362":4}}],["newnode",{"2":{"300":26}}],["newhtml=",{"2":{"347":2}}],["newobj",{"2":{"319":6,"527":12}}],["newarr2",{"2":{"527":2}}],["newarr1",{"2":{"527":2}}],["newarray",{"2":{"392":3,"393":6}}],["newarr",{"2":{"316":18,"319":12,"381":4}}],["newinstance",{"2":{"278":8}}],["newitem",{"2":{"96":10}}],["newitemevent",{"2":{"96":8}}],["new运算符是创建对象时",{"2":{"278":1}}],["new运算符",{"0":{"278":1}}],["newfn",{"2":{"262":2}}],["newquery",{"2":{"157":4}}],["newvalue",{"2":{"118":2}}],["new",{"0":{"498":1},"2":{"9":2,"11":2,"13":4,"15":12,"45":2,"46":2,"61":4,"96":4,"113":2,"116":4,"125":2,"126":2,"156":2,"239":8,"240":2,"242":4,"250":2,"265":2,"266":4,"268":2,"271":2,"288":2,"293":2,"294":4,"295":6,"296":4,"298":10,"299":14,"300":4,"302":2,"303":2,"307":2,"308":4,"310":2,"311":4,"312":4,"313":6,"314":6,"315":12,"316":8,"318":6,"319":14,"322":4,"323":2,"324":8,"329":4,"330":4,"331":2,"332":2,"333":2,"335":2,"374":2,"406":6,"407":2,"409":2,"410":2,"418":4,"426":2,"429":1,"432":1,"438":1,"493":4,"494":4,"495":2,"498":4,"499":2,"502":2,"503":4,"504":2,"519":2,"525":4,"527":4,"533":4,"551":6,"572":4,"577":4,"578":2,"584":2,"615":2}}],["五",{"0":{"8":1,"26":1,"51":1,"307":1,"411":1,"455":1,"460":1},"1":{"9":1,"10":1,"11":1,"12":1,"13":1,"456":1,"457":1,"458":1,"459":1,"460":1,"461":1,"462":1,"463":1,"464":1,"465":1,"466":1},"2":{"302":6}}],["吃饭",{"2":{"7":2}}],["mvc",{"2":{"553":1}}],["mvvm",{"2":{"553":1}}],["m",{"2":{"301":10,"345":2,"395":2,"553":1,"578":2}}],["m+n",{"2":{"292":2}}],["ms",{"2":{"177":2}}],["msg",{"2":{"9":2,"10":2,"11":2,"12":4,"42":10}}],["md$",{"2":{"599":4}}],["md文",{"2":{"596":1}}],["mdn",{"2":{"336":2}}],["md",{"2":{"221":1,"489":1,"599":2}}],["md它选中的是组件模板标签",{"2":{"98":1}}],["md5",{"2":{"13":6,"15":2}}],["mutationobserver",{"2":{"615":1}}],["must",{"2":{"592":1}}],["music",{"2":{"318":6,"319":10,"573":4}}],["mul3",{"2":{"540":6}}],["multer",{"2":{"46":8}}],["multiply",{"2":{"297":16}}],["multiple",{"2":{"46":2}}],["multipart",{"2":{"45":2,"46":2}}],["multi",{"2":{"7":4}}],["mubt",{"2":{"55":6}}],["m=",{"2":{"55":2}}],["mirror",{"2":{"396":2}}],["mirrors",{"2":{"51":2}}],["microsoft",{"2":{"231":2}}],["mixin适用于将一组样式应用于多个选择器",{"2":{"491":1}}],["mixin中的样式复制到",{"2":{"491":1}}],["mixin会直接将",{"2":{"491":1}}],["mixin",{"0":{"491":1},"2":{"195":3,"488":1,"491":6}}],["mixins混入",{"2":{"554":1}}],["mixins的原理",{"0":{"554":1}}],["mixins",{"0":{"157":1},"2":{"158":2}}],["minchunks",{"2":{"571":4}}],["minsize",{"2":{"571":6}}],["mini",{"2":{"489":1,"610":2}}],["minimum",{"2":{"489":1}}],["minindex",{"2":{"288":10}}],["minute",{"2":{"268":2}}],["minmax",{"2":{"165":2}}],["min",{"2":{"139":2,"202":2,"489":5,"493":6,"494":2,"603":2}}],["middle",{"2":{"577":2,"578":8,"580":2,"611":2}}],["midjourney实现",{"0":{"551":1}}],["mid",{"2":{"15":6,"292":8}}],["mkdirsync",{"2":{"46":2,"599":2}}],["myref",{"2":{"145":2}}],["myref2",{"2":{"145":2}}],["myclass",{"2":{"278":4}}],["mycomponent",{"2":{"139":6,"140":5}}],["mycontext",{"2":{"114":10}}],["mycontent",{"2":{"114":6}}],["mycpncomponent",{"2":{"95":2,"96":2}}],["mycpn",{"2":{"95":10,"96":6}}],["mybox",{"2":{"104":6}}],["my",{"2":{"64":4,"84":2,"222":1,"224":4,"227":4,"229":1,"230":3,"303":2,"572":6,"573":4}}],["myubt",{"2":{"55":2}}],["mydb01",{"2":{"34":2}}],["mysql",{"0":{"34":1},"2":{"34":9,"211":12}}],["mw2",{"2":{"29":6}}],["mw1被访问哈哈哈",{"2":{"29":4}}],["mw1被访问",{"2":{"29":2}}],["mw1",{"2":{"29":16}}],["mw",{"2":{"29":8}}],["m2",{"2":{"25":4}}],["m1",{"2":{"25":19}}],["media",{"2":{"489":5,"603":4}}],["merged",{"2":{"292":20}}],["mergearr",{"2":{"292":10}}],["merge",{"2":{"205":2,"217":1,"292":8}}],["method1",{"2":{"427":2}}],["methods",{"2":{"158":2,"554":1,"615":2}}],["method=",{"2":{"46":2}}],["method",{"2":{"20":2,"22":4,"426":2,"589":2}}],["message",{"2":{"16":4,"18":2,"30":4,"34":2,"35":2,"36":6,"37":4,"38":4,"43":10,"159":4,"495":7}}],["may",{"2":{"551":2}}],["male",{"2":{"400":2}}],["mailreg",{"2":{"346":2}}],["main",{"2":{"105":4,"202":2,"396":4}}],["make",{"2":{"234":2,"586":2}}],["master",{"2":{"211":8,"213":4,"229":1,"395":2,"396":8}}],["manual",{"2":{"197":2,"234":2}}],["manager",{"2":{"51":2}}],["mar",{"2":{"533":2}}],["markdown",{"2":{"147":2,"601":2}}],["markforcheck",{"2":{"112":2}}],["margin和padding适用场景",{"0":{"482":1}}],["margin",{"2":{"15":2,"113":2,"178":2,"189":2,"190":2,"195":2,"474":7,"475":1,"482":4,"603":2}}],["madao",{"2":{"86":2}}],["mat",{"2":{"347":6}}],["matchall",{"0":{"349":1},"2":{"349":2}}],["match",{"2":{"36":2,"302":2,"341":2,"345":8,"346":2,"347":6,"349":2,"350":2,"530":1,"571":2}}],["math",{"2":{"15":2,"107":2,"159":2,"267":14,"288":4,"289":2,"291":4,"292":4,"297":4,"302":4,"365":2,"373":2,"384":2,"493":2,"494":2,"506":1,"513":1,"578":4,"583":4}}],["maxwidth",{"2":{"578":6,"610":2}}],["maxinitialrequests",{"2":{"571":2}}],["maxnum",{"2":{"494":4}}],["max++",{"2":{"493":2}}],["max",{"2":{"15":4,"201":2,"258":2,"493":6,"603":2,"610":2}}],["maproot",{"2":{"440":2}}],["mapforeach",{"2":{"392":1,"393":4}}],["mapstring",{"2":{"371":4}}],["mapstate",{"2":{"157":4}}],["map取出右括号匹配的括号类型",{"2":{"279":2}}],["map2",{"2":{"265":2}}],["map中任何类型的值都可以称为数据的key",{"2":{"265":1}}],["map和object的主要区别",{"2":{"265":1}}],["map用来存储键值对结构的数据",{"2":{"265":1}}],["map等方法",{"2":{"243":1}}],["map",{"0":{"265":1},"2":{"15":2,"137":1,"146":1,"157":2,"245":6,"246":6,"265":26,"279":4,"296":2,"302":6,"307":4,"314":2,"315":6,"316":2,"327":2,"347":4,"349":4,"350":2,"368":4,"370":4,"371":2,"372":2,"373":2,"374":2,"375":2,"440":4,"494":2,"532":16,"585":2,"599":2}}],["mounted",{"0":{"558":1},"2":{"151":2,"152":2,"153":2,"555":2,"556":4,"559":2,"577":1,"584":2,"612":2,"615":1}}],["mouseleave",{"2":{"125":2}}],["mouseenter",{"2":{"125":2}}],["mouseevent",{"2":{"93":2}}],["mouse",{"2":{"111":1,"112":1}}],["mono",{"2":{"230":1,"231":2}}],["mono字体",{"2":{"225":1}}],["monospace",{"2":{"198":2}}],["monaco",{"2":{"198":2}}],["monthstr",{"2":{"294":4}}],["months",{"2":{"294":4}}],["month",{"2":{"46":4,"268":2,"294":6}}],["mongdb数据库连接成功",{"2":{"13":2}}],["mongdb数据库连接失败",{"2":{"13":2}}],["mongo",{"2":{"55":2}}],["mongoose",{"2":{"10":2,"13":28}}],["mongodb是文档型的nosql数据库",{"2":{"0":1}}],["modal=",{"2":{"609":2}}],["modes",{"2":{"577":2}}],["mode",{"2":{"573":2}}],["model=",{"2":{"610":2}}],["model",{"2":{"13":6,"157":4,"553":1}}],["module不需要使用特定的函数或语法来定义和导入模块",{"2":{"549":1}}],["module等",{"2":{"549":1}}],["modulea",{"2":{"433":8}}],["moduleb",{"2":{"432":20}}],["moduleresolution",{"0":{"432":1},"2":{"440":2}}],["modules",{"2":{"357":2,"414":2,"418":2,"423":2,"439":2,"440":2,"563":2,"564":3,"571":4,"613":2}}],["module",{"0":{"24":1,"430":1},"2":{"13":8,"24":1,"25":8,"30":2,"77":1,"80":2,"149":1,"220":4,"414":4,"418":4,"419":2,"423":2,"440":2,"488":2,"549":1,"570":2,"571":4,"573":1}}],["gzip",{"0":{"613":1},"2":{"613":2}}],["g6",{"2":{"577":4,"578":22}}],["global",{"2":{"535":1}}],["gmt+0800",{"2":{"533":2}}],["gmail",{"2":{"233":1}}],["gpu",{"2":{"463":2,"464":1}}],["ghpages",{"2":{"396":2}}],["gh",{"2":{"395":4,"396":2}}],["gi",{"2":{"341":2,"346":4,"347":2,"349":2}}],["gitlab\\t",{"2":{"235":2}}],["gitlab主机名",{"2":{"235":2}}],["gitlab",{"2":{"235":6}}],["gitlab添加",{"2":{"233":1}}],["gitee",{"2":{"211":23,"229":1,"233":1,"235":2,"396":34}}],["git",{"0":{"218":1,"219":1},"1":{"219":1,"220":1,"221":1},"2":{"205":9,"206":6,"207":8,"208":2,"209":2,"210":2,"211":56,"212":4,"213":6,"214":8,"216":1,"217":5,"218":3,"234":1,"235":6,"357":2,"395":12,"396":10}}],["git常用操作",{"0":{"204":1},"1":{"205":1,"206":1,"207":1,"208":1,"209":1,"210":1,"211":1,"212":1,"213":1,"214":1,"215":1,"216":1,"217":1,"218":1,"219":1,"220":1,"221":1}}],["git提交规范等",{"2":{"149":1}}],["github代码拉取深度",{"2":{"396":2}}],["github主机名",{"2":{"235":2}}],["github主机地址",{"2":{"235":2}}],["github",{"2":{"66":2,"211":14,"233":1,"234":4,"235":9,"395":2,"396":11}}],["gu",{"2":{"345":6}}],["guangdong",{"2":{"318":6,"319":10}}],["guid",{"2":{"231":2}}],["guide",{"2":{"161":1}}],["gcd",{"2":{"284":4}}],["gap",{"2":{"166":8,"168":2,"170":2,"291":22}}],["garden",{"2":{"161":1}}],["gender",{"2":{"269":8,"270":4,"399":2}}],["generatorrunner",{"2":{"525":2}}],["generator",{"0":{"524":1},"1":{"525":1},"2":{"161":1,"414":2,"525":16}}],["getletterwidth",{"2":{"578":2}}],["getpoint",{"2":{"578":4}}],["getprototypeof",{"2":{"274":1}}],["getshapestyle",{"2":{"578":4}}],["getselection",{"2":{"574":4}}],["getsnapshotbeforeupdate",{"2":{"147":1}}],["getelementsbytagname",{"2":{"374":2}}],["getelementbyid",{"2":{"137":2,"139":2,"140":2,"143":2,"144":8,"145":2,"577":4}}],["getimagecode",{"2":{"589":2}}],["getimages",{"2":{"374":6}}],["getimgcode",{"2":{"589":2}}],["getitem",{"2":{"523":4}}],["getinfo",{"2":{"43":2}}],["getfile",{"2":{"333":2,"334":2,"357":2}}],["getfullyear",{"2":{"46":2,"294":2}}],["getuint8",{"2":{"332":8}}],["gettextsize",{"2":{"578":2}}],["getter方法",{"2":{"270":2}}],["gettime",{"2":{"316":2,"318":4}}],["getname",{"2":{"270":4}}],["getattribute",{"2":{"249":2,"250":2,"374":2}}],["getarticles",{"2":{"12":2}}],["getarticlebyid",{"2":{"12":2}}],["getboundingclientrect",{"2":{"249":2}}],["getcurrentstyle",{"2":{"541":4}}],["getcss",{"2":{"541":16}}],["getcatch",{"2":{"242":2}}],["getcontent",{"2":{"577":2}}],["getcontext",{"2":{"551":2}}],["getcontainer",{"2":{"113":4}}],["getcomputedstyle",{"2":{"541":8}}],["getcollection",{"2":{"4":6,"5":4,"6":4,"7":2}}],["getdirdata",{"2":{"357":6}}],["getderivedstatefromprops",{"2":{"147":1}}],["getdate",{"2":{"46":2}}],["getval",{"2":{"84":4,"118":2}}],["getmonths",{"2":{"294":2}}],["getmonth",{"2":{"46":2,"294":2}}],["get",{"2":{"28":2,"29":10,"30":6,"42":2,"43":2,"46":2,"55":4,"113":2,"265":2,"270":4,"296":14,"407":2,"512":2,"536":4,"578":10}}],["g",{"0":{"345":1},"2":{"157":6,"221":2,"302":4,"345":2,"350":2,"400":6,"599":2}}],["greeter",{"2":{"412":2}}],["green",{"2":{"399":6,"481":2}}],["grep",{"2":{"51":2,"62":2,"72":1,"73":2}}],["graphbehaviors",{"2":{"577":4}}],["graph",{"2":{"577":18}}],["grape",{"2":{"123":10}}],["gray",{"2":{"199":4}}],["gradient",{"2":{"179":2,"186":8,"195":8,"198":2,"199":2,"478":7,"481":2}}],["grid布局",{"0":{"164":1},"2":{"474":1}}],["grid布局学习笔记",{"0":{"160":1},"1":{"161":1,"162":1,"163":1,"164":1,"165":1,"166":1,"167":1,"168":1,"169":1,"170":1,"171":1,"172":1,"173":1,"174":1}}],["grid",{"2":{"161":3,"164":2,"165":7,"166":6,"168":16,"170":16,"172":22,"173":14,"474":7,"482":1}}],["gridloading",{"2":{"158":4}}],["groupbytypes",{"2":{"577":2}}],["group",{"2":{"157":4,"578":58,"580":2}}],["gt",{"2":{"7":10,"9":2,"10":2,"11":2,"12":4,"13":2,"15":54,"20":4,"21":16,"22":20,"28":4,"29":24,"30":6,"34":2,"35":2,"36":6,"37":8,"38":8,"42":6,"43":2,"45":16,"46":20,"59":2,"61":8,"75":2,"84":16,"86":18,"87":8,"88":4,"89":24,"90":26,"91":12,"92":32,"93":8,"95":16,"96":18,"98":4,"102":34,"104":32,"105":40,"106":40,"107":28,"108":12,"109":1,"113":26,"114":86,"116":52,"117":20,"118":12,"119":4,"121":62,"122":40,"123":96,"124":14,"125":2,"126":28,"128":4,"129":4,"130":16,"133":4,"135":4,"137":12,"139":36,"140":7,"143":8,"144":40,"145":20,"146":16,"147":14,"150":6,"151":16,"152":16,"153":16,"157":8,"159":4,"168":16,"170":16,"172":4,"173":8,"174":4,"178":16,"210":2,"220":2,"222":1,"225":1,"238":8,"239":18,"243":2,"246":6,"247":14,"249":4,"250":6,"255":14,"256":14,"257":8,"258":2,"262":2,"264":2,"265":4,"267":2,"274":2,"276":2,"282":4,"283":2,"287":2,"288":2,"290":4,"291":2,"292":2,"293":8,"295":24,"296":2,"297":6,"300":4,"301":4,"302":8,"303":26,"305":4,"306":4,"307":16,"308":24,"309":4,"310":14,"311":16,"312":4,"313":16,"314":18,"315":40,"316":18,"318":4,"322":12,"323":4,"324":10,"326":16,"327":12,"328":12,"331":2,"333":4,"334":8,"335":16,"346":38,"347":44,"348":4,"349":32,"350":8,"357":12,"362":2,"364":4,"365":2,"371":6,"372":2,"373":4,"374":4,"375":2,"380":4,"381":2,"382":4,"383":4,"384":2,"385":4,"388":1,"389":2,"393":2,"396":13,"399":4,"400":2,"402":2,"424":8,"428":4,"434":2,"449":5,"450":3,"471":2,"478":16,"482":20,"493":10,"494":14,"495":2,"500":4,"507":3,"509":8,"510":2,"512":16,"519":4,"520":8,"525":4,"528":2,"536":2,"539":22,"540":10,"543":10,"544":4,"551":28,"574":2,"577":22,"578":36,"579":2,"584":8,"586":14,"587":8,"599":18,"605":2,"609":18,"610":46,"614":14}}],["u9fa5",{"2":{"578":2}}],["u4e00",{"2":{"578":2}}],["ue603",{"2":{"578":2}}],["ue605",{"2":{"578":2}}],["ue606",{"2":{"578":2}}],["ue604",{"2":{"578":4}}],["ui全局引入改为按需引入",{"2":{"609":1}}],["ui",{"2":{"574":2,"588":1}}],["uglifyjsplugin",{"2":{"548":1}}],["umd",{"2":{"414":2,"430":1,"440":2}}],["u",{"2":{"345":2,"547":2}}],["uuid",{"2":{"159":4}}],["ul",{"2":{"122":8,"144":8,"577":4}}],["ub",{"2":{"59":2}}],["ubuntu",{"2":{"56":2,"70":1,"396":2}}],["ub01",{"2":{"56":2}}],["uno",{"2":{"586":2,"587":2}}],["unobserve",{"2":{"250":2}}],["unbind",{"2":{"574":2}}],["uncaught",{"0":{"586":1},"1":{"587":1},"2":{"509":1,"516":1,"551":2,"588":1}}],["unicode",{"2":{"387":1}}],["union",{"2":{"322":8,"326":6}}],["uniquearr",{"2":{"316":22,"319":4}}],["units",{"2":{"302":4}}],["unit",{"2":{"302":18}}],["unitmap",{"2":{"302":4}}],["unable",{"2":{"234":1}}],["unauthorizederror",{"2":{"43":2}}],["unmountcomponentatnode",{"2":{"147":4}}],["un",{"2":{"126":10}}],["unknown与any区别",{"2":{"400":1}}],["unknown",{"2":{"126":2,"357":2,"400":4}}],["undefined的赋值",{"2":{"434":1}}],["undefined\\t",{"2":{"255":2,"399":2}}],["undefined进行保护",{"2":{"133":1}}],["undefined",{"0":{"586":1},"1":{"587":1},"2":{"89":2,"251":2,"257":4,"261":2,"278":1,"318":11,"322":2,"434":6,"506":1,"507":1,"509":3,"511":1,"512":3,"519":2,"524":2,"533":1,"588":1}}],["unlessdirective",{"2":{"126":2}}],["unlesscontext",{"2":{"126":4}}],["unless",{"2":{"43":2,"126":12}}],["usage",{"2":{"418":4,"423":2}}],["us",{"2":{"268":2}}],["usr",{"2":{"61":2,"66":2,"395":2}}],["ustr",{"2":{"37":8,"302":6}}],["usefetch",{"2":{"589":2}}],["useeffect",{"2":{"551":2}}],["usebuiltins",{"2":{"418":2,"423":2}}],["uses",{"2":{"396":10}}],["useref",{"2":{"551":2}}],["userinfo",{"2":{"43":10}}],["username=yunzhishangfxj",{"2":{"55":2}}],["username",{"2":{"12":2,"13":2,"42":8,"43":6,"146":8,"396":2}}],["user",{"2":{"9":16,"12":6,"13":9,"34":2,"37":12,"38":6,"42":4,"43":8,"61":4}}],["userspaceonuse",{"2":{"178":2}}],["userstreams",{"2":{"122":2}}],["usersession",{"2":{"42":2}}],["userschema",{"2":{"13":4}}],["users",{"2":{"2":4,"4":44,"5":14,"6":10,"7":8,"35":2,"36":4,"37":4,"38":4,"222":1}}],["use",{"2":{"1":4,"29":4,"30":6,"42":6,"43":8,"46":2,"414":2,"418":2,"423":2,"440":2}}],["url=",{"2":{"573":4}}],["urlencoded",{"2":{"30":2,"42":2,"43":2}}],["url",{"0":{"335":1,"592":1},"1":{"593":1,"594":1},"2":{"21":10,"22":20,"178":2,"211":8,"335":24,"478":2,"551":8,"573":1,"590":1,"592":2}}],["url+",{"2":{"20":2}}],["utf",{"2":{"22":4,"491":2}}],["utf8",{"2":{"16":4}}],["utils",{"2":{"51":2}}],["util",{"2":{"13":2,"433":2,"578":4}}],["upper",{"2":{"302":14}}],["uppercasepipe",{"2":{"132":1}}],["upstream",{"2":{"209":4}}],["upsert",{"2":{"7":2}}],["uploads",{"2":{"46":2}}],["uploadchunks",{"2":{"15":4}}],["upload",{"2":{"15":10,"45":2,"46":13}}],["updtedat",{"2":{"13":2}}],["updert",{"2":{"7":2}}],["updatetext",{"2":{"610":2}}],["updated",{"2":{"555":2}}],["updatearticle",{"2":{"11":2}}],["update",{"2":{"7":12,"38":2,"55":2,"610":2}}],["436",{"2":{"578":2}}],["442",{"2":{"578":2}}],["448",{"2":{"578":6}}],["4853",{"2":{"578":2}}],["489",{"2":{"578":4}}],["48",{"2":{"578":4}}],["4以上并且安装atom",{"2":{"440":2}}],["456",{"2":{"408":2,"527":2}}],["45deg",{"2":{"179":2,"186":2,"481":4}}],["494",{"2":{"578":2}}],["49",{"2":{"370":2}}],["4const",{"2":{"296":1}}],["4=4",{"2":{"296":2}}],["4f2a",{"2":{"231":2}}],["4px",{"2":{"191":1,"603":4}}],["4em",{"2":{"185":4}}],["4kb",{"2":{"41":1,"522":1}}],["4",{"0":{"7":1,"12":1,"37":1,"43":1,"87":1,"235":1,"254":1,"343":1,"419":1,"429":1},"2":{"26":1,"137":2,"147":9,"172":2,"193":2,"195":2,"210":2,"282":12,"288":2,"296":7,"298":2,"299":10,"302":2,"303":2,"304":2,"319":2,"321":2,"322":4,"324":6,"332":2,"346":2,"350":2,"363":2,"364":22,"365":2,"370":4,"372":4,"378":1,"380":4,"381":6,"383":4,"393":2,"399":6,"409":2,"410":2,"424":2,"432":2,"448":3,"450":1,"482":1,"495":2,"532":16,"539":4,"564":1,"577":2,"578":6}}],["40px",{"2":{"190":2,"603":2}}],["401",{"2":{"43":2}}],["400",{"2":{"43":2,"493":2,"494":2}}],["404",{"2":{"21":2,"22":4}}],["40",{"2":{"4":2}}],["547",{"2":{"578":2}}],["546",{"2":{"578":2}}],["5707",{"2":{"578":2}}],["576",{"2":{"578":6}}],["57",{"2":{"578":2}}],["574e775e",{"2":{"231":2}}],["59",{"2":{"578":2}}],["598",{"2":{"578":2}}],["51",{"2":{"578":4}}],["5个按钮",{"2":{"536":2}}],["5m",{"2":{"522":2}}],["56",{"2":{"490":2,"533":2,"578":2}}],["58",{"2":{"418":2,"423":2}}],["58a",{"2":{"186":18}}],["55",{"2":{"285":2}}],["5b96",{"2":{"231":2}}],["5s",{"2":{"203":4}}],["5em",{"2":{"195":6,"198":2}}],["52",{"2":{"190":6,"585":4}}],["5c7aea",{"2":{"189":2}}],["5px",{"2":{"177":6,"183":2,"192":12}}],["50",{"2":{"91":2,"113":2,"156":2,"165":1,"179":4,"186":2,"188":4,"195":4,"198":4,"201":2,"362":4,"474":8,"481":2}}],["50px",{"2":{"91":2,"92":6,"168":4,"189":2}}],["5000",{"2":{"240":2}}],["500px",{"2":{"201":2,"481":4}}],["500",{"2":{"43":2,"314":2,"493":2,"494":2,"519":8}}],["5",{"0":{"13":1,"38":1,"88":1,"255":1,"344":1,"420":1,"430":1},"2":{"5":2,"55":2,"137":2,"147":2,"178":10,"191":1,"251":4,"282":8,"285":2,"288":2,"297":8,"298":2,"299":10,"319":2,"322":4,"324":6,"350":2,"363":4,"364":10,"365":2,"370":2,"375":2,"383":4,"399":2,"432":2,"448":1,"482":1,"536":2,"539":2,"578":12,"585":4}}],["缘一1",{"2":{"5":2}}],["缘一",{"2":{"5":2}}],["对前者的属性进行拷贝扩展",{"2":{"554":1}}],["对mvvm的理解",{"0":{"553":1}}],["对",{"2":{"552":1,"554":1}}],["对该子节点的所有子节点",{"2":{"543":1}}],["对根节点的所有子节点",{"2":{"543":1}}],["对构造函数有返回值的处理判断",{"2":{"498":1}}],["对使用vuex",{"2":{"427":1}}],["对初期使用typescript的同学而言",{"2":{"425":1}}],["对书写typescript代码十分重要",{"2":{"425":1}}],["对于监听",{"2":{"495":1}}],["对于一些简单的图标和装饰性元素",{"2":{"486":1}}],["对于一些不希望被任意修改的属性",{"2":{"407":1}}],["对于较大的图片",{"2":{"485":1}}],["对于工程项目",{"2":{"432":1}}],["对于例如",{"2":{"422":1}}],["对于空数组是不会执行回调函数的",{"2":{"377":1}}],["对原数组的加工",{"2":{"367":1}}],["对比键的数量",{"2":{"318":1}}],["对比项的数量",{"2":{"318":1}}],["对比语法",{"2":{"4":1}}],["对距离为",{"2":{"291":2}}],["对非布尔值值取反",{"2":{"255":2}}],["对布尔值值取反",{"2":{"255":2}}],["对标签属性进行类型",{"2":{"144":2}}],["对null",{"2":{"133":1}}],["对父组件样式也能生效",{"2":{"101":1}}],["对应的目录下添加",{"2":{"596":1}}],["对应的脚本并执行对应命令",{"2":{"563":1,"564":1}}],["对应",{"2":{"46":2}}],["对象上",{"2":{"615":1}}],["对象就在",{"2":{"525":2}}],["对象就是一个用来存储不同属性的容器",{"2":{"270":1}}],["对象转换成可阅读的字符串",{"2":{"533":1}}],["对象转为数字会经历",{"2":{"512":2}}],["对象转字符串",{"2":{"512":1}}],["对象与对象",{"2":{"512":1}}],["对象与字符串",{"2":{"512":1}}],["对象唯一值属性",{"2":{"506":1}}],["对象里的属性求和",{"0":{"384":1}}],["对象数组",{"0":{"325":1},"1":{"326":1,"327":1,"328":1}}],["对象数组去重",{"0":{"317":1,"319":1},"1":{"318":1,"319":1}}],["对象相同比较",{"0":{"318":1}}],["对象中的数据",{"2":{"274":1}}],["对象中还有一些内容",{"2":{"274":1}}],["对象中存储属性的区域实际有两个",{"2":{"274":1}}],["对象自身不包含该属性时",{"2":{"274":1}}],["对象自身",{"2":{"274":1}}],["对象的执行过程",{"0":{"498":1}}],["对象的分类",{"2":{"278":1}}],["对象的构造函数",{"2":{"274":1}}],["对象的结构",{"0":{"273":1},"1":{"274":1,"275":1,"276":1,"277":1}}],["对象的中间件",{"2":{"43":2}}],["对象不仅存储属性",{"2":{"270":1}}],["对象",{"0":{"24":1},"2":{"29":1,"261":2,"274":1,"277":2,"399":2,"560":1}}],["对事务要求不高",{"2":{"0":1}}],["去掉",{"2":{"590":2}}],["去找",{"2":{"564":1}}],["去映射的路径下加载模块",{"2":{"433":1}}],["去重",{"2":{"4":1}}],["去除重复元素依靠的是indexof总是返回第一个元素的位置",{"2":{"364":2}}],["去除特定字段",{"2":{"4":2}}],["去除id字段",{"2":{"4":2}}],["降序",{"2":{"4":2}}],["升序",{"2":{"4":2}}],["喜好",{"2":{"4":2}}],["数值数组",{"2":{"399":2}}],["数字",{"2":{"510":2}}],["数字序列转为数组",{"0":{"373":1}}],["数字过大",{"2":{"302":2}}],["数字超过999999999999则报错",{"2":{"302":2}}],["数字转中文",{"0":{"302":1}}],["数字转百分比",{"2":{"132":1}}],["数字转字符串",{"2":{"132":1}}],["数组劫持原理",{"0":{"552":1}}],["数组求和",{"0":{"380":1},"2":{"539":1}}],["数组去重",{"0":{"364":1,"381":1}}],["数组转map",{"2":{"265":1}}],["数组中当前被处理的元素",{"2":{"378":1}}],["数组中正在处理的当前元素的索引",{"2":{"368":2}}],["数组中正在处理的当前元素",{"2":{"368":2}}],["数组中",{"2":{"82":2}}],["数组中列出的组件",{"2":{"82":2}}],["数组中声名",{"2":{"79":2}}],["数组中的查询",{"2":{"4":1}}],["数组",{"0":{"79":1,"80":1,"81":1,"82":1},"2":{"399":1,"527":2}}],["数组大小为3",{"2":{"4":1}}],["数组大小为3db",{"2":{"4":1}}],["数据修改自动触发视图更新",{"2":{"553":1}}],["数据",{"2":{"542":2}}],["数据长期保留",{"2":{"522":1}}],["数据劫持",{"2":{"512":2}}],["数据类型转换",{"0":{"508":1},"1":{"509":1,"510":1,"511":1}}],["数据类型",{"0":{"261":1,"506":1},"1":{"507":1}}],["数据库名",{"2":{"1":2}}],["数据库操作",{"0":{"1":1}}],["数据量大",{"2":{"0":1}}],["张三",{"2":{"35":2,"122":2,"502":2,"503":2,"504":2}}],["张",{"2":{"4":6}}],["27",{"2":{"578":2}}],["277",{"2":{"578":6}}],["262",{"2":{"578":2}}],["266",{"2":{"578":6}}],["2600",{"2":{"493":2,"494":2}}],["2d",{"2":{"551":2}}],["298",{"2":{"578":4}}],["29",{"2":{"494":2}}],["295deg",{"2":{"193":2}}],["2xl",{"2":{"489":1}}],["23",{"2":{"527":2,"578":2}}],["234",{"2":{"385":4}}],["230",{"2":{"198":6}}],["2const",{"2":{"382":1}}],["2=2",{"2":{"296":2}}],["2\\t",{"2":{"255":2,"257":4}}],["2em",{"2":{"195":6}}],["25s",{"2":{"603":2}}],["25",{"2":{"186":2,"370":2,"490":2}}],["255",{"2":{"179":18}}],["2px",{"2":{"183":2,"191":1,"457":1}}],["2s",{"2":{"179":2}}],["2fr",{"2":{"165":1}}],["211",{"2":{"589":4}}],["21const",{"2":{"539":1}}],["210deg",{"2":{"195":2}}],["21",{"2":{"36":2,"268":2,"285":2,"539":3}}],["2m",{"2":{"15":2}}],["2",{"0":{"5":1,"10":1,"21":1,"25":1,"29":1,"32":1,"35":1,"41":1,"55":1,"67":1,"71":1,"85":1,"117":1,"228":1,"233":1,"252":1,"341":1,"417":1,"423":1,"427":1},"2":{"15":12,"35":2,"36":2,"38":2,"46":2,"66":2,"79":2,"80":2,"92":1,"103":2,"107":2,"108":2,"125":2,"137":8,"139":2,"140":1,"143":2,"145":4,"146":1,"147":21,"159":2,"172":10,"195":4,"198":2,"203":2,"210":2,"231":4,"243":9,"256":2,"257":4,"268":8,"270":2,"281":2,"282":8,"285":6,"288":2,"289":2,"291":4,"292":16,"294":2,"295":4,"296":10,"298":2,"299":10,"303":2,"304":2,"315":2,"316":10,"319":18,"321":4,"322":6,"323":2,"324":4,"329":4,"330":4,"341":2,"346":4,"349":2,"363":4,"364":10,"365":6,"370":2,"372":4,"373":4,"378":1,"380":4,"381":4,"382":7,"383":4,"385":4,"389":8,"399":8,"424":2,"426":1,"432":4,"448":1,"468":1,"482":5,"495":2,"512":4,"531":2,"533":4,"539":8,"540":2,"542":8,"571":4,"577":6,"578":18,"599":2,"602":1}}],["222",{"2":{"578":2}}],["22",{"2":{"4":2,"35":2,"385":4,"504":2,"578":2}}],["206",{"2":{"578":2}}],["2015",{"2":{"440":2}}],["2048",{"2":{"402":2}}],["2023",{"2":{"533":2}}],["2022",{"2":{"318":6,"319":10,"346":6}}],["2021",{"2":{"268":2}}],["20px",{"2":{"113":4,"166":6,"178":2,"184":4,"186":4,"189":2,"195":2,"479":1}}],["200deg",{"2":{"481":4}}],["20000",{"2":{"571":2}}],["2000",{"2":{"295":2,"578":2}}],["200px",{"2":{"92":6,"158":2,"165":3,"178":2,"190":2,"195":2,"610":2,"611":2}}],["200",{"2":{"20":2,"30":4,"43":4,"179":6,"578":2}}],["20",{"2":{"4":2,"6":2,"25":4,"29":4,"156":2,"165":2,"262":2,"332":4,"362":4,"365":2,"384":2,"389":8,"503":2}}],["24px",{"2":{"577":2}}],["240deg",{"2":{"195":2}}],["24",{"2":{"4":2,"7":8,"178":4,"495":2,"578":2}}],["pt",{"2":{"488":1}}],["python",{"2":{"393":2}}],["php",{"2":{"393":2}}],["phone",{"2":{"130":10}}],["p0",{"2":{"346":2}}],["png等",{"2":{"484":1}}],["png",{"2":{"333":2,"374":6,"551":8}}],["pnpm",{"2":{"220":4,"564":1}}],["p的状态就跟着改变",{"2":{"314":1}}],["pwsh",{"2":{"224":2,"227":2,"231":2}}],["pending",{"2":{"303":6,"304":10,"307":4,"308":2,"310":2,"311":2,"315":12}}],["pear",{"2":{"123":10,"364":4}}],["perspective",{"2":{"479":1}}],["persist",{"2":{"396":2}}],["person",{"2":{"133":2,"144":20,"269":2,"270":2,"272":2,"276":2,"404":2,"405":2,"406":18,"407":4,"412":10,"498":10}}],["persons",{"2":{"122":4}}],["permission",{"2":{"234":2}}],["percentpipe",{"2":{"132":1}}],["percent",{"2":{"15":4}}],["p3之中有一个实例率先改变状态",{"2":{"314":1}}],["p3",{"2":{"122":2,"295":4,"314":2}}],["p2",{"2":{"122":2,"295":4,"313":4,"314":7,"346":2}}],["p1",{"2":{"122":2,"295":4,"303":4,"307":4,"313":4,"314":6,"346":4,"347":4,"407":6}}],["pinia",{"2":{"506":1}}],["pink",{"2":{"203":2}}],["pie",{"2":{"481":2}}],["piece",{"2":{"177":2}}],["pi",{"2":{"408":4}}],["pivot",{"2":{"289":6}}],["pivotindex",{"2":{"289":4}}],["pipes",{"2":{"577":2}}],["pipe2",{"2":{"108":4}}],["pipe2pipe",{"2":{"108":3}}],["pipepowpipe",{"2":{"107":2}}],["pipepow",{"2":{"107":10}}],["pipetransform",{"2":{"107":4,"108":4}}],["pipe",{"2":{"107":4,"108":4,"112":1}}],["pick",{"2":{"210":2,"214":2,"216":2}}],["picinfo",{"2":{"88":2}}],["picurl",{"2":{"88":2}}],["px转为vh的函数",{"2":{"583":2}}],["px转为vw的函数",{"2":{"583":2}}],["px",{"2":{"91":2,"116":16,"458":1}}],["pkill",{"2":{"72":1}}],["psdregs",{"2":{"348":6}}],["ps",{"2":{"51":2,"56":6,"72":1,"225":1}}],["please",{"2":{"234":2}}],["placeholder",{"2":{"602":2}}],["placeholder=",{"2":{"108":2,"130":4,"610":2}}],["place",{"2":{"168":2,"174":2}}],["plain",{"2":{"20":2,"302":6,"329":2,"330":2}}],["plugins",{"2":{"418":2,"570":2,"577":2,"602":2,"613":2}}],["pluginnpm",{"2":{"417":1}}],["plugin",{"2":{"51":2,"417":1,"418":8,"548":3,"570":1,"601":2,"602":2}}],["purple",{"2":{"481":2}}],["pure",{"2":{"108":2}}],["put",{"2":{"296":10}}],["pub",{"2":{"233":1}}],["pub文件",{"2":{"233":1}}],["publicpath",{"0":{"573":1},"2":{"573":7}}],["publickey",{"2":{"234":2,"235":4}}],["public",{"2":{"46":2,"229":1,"406":6,"599":2}}],["pull前",{"2":{"213":2}}],["pull",{"2":{"55":2,"205":1,"209":2,"213":4,"214":4}}],["pushgit",{"2":{"214":1}}],["push",{"2":{"15":12,"55":2,"96":2,"108":2,"157":8,"206":2,"207":2,"211":8,"214":1,"217":1,"279":4,"282":2,"288":2,"289":4,"292":12,"293":2,"294":2,"299":6,"308":2,"310":2,"311":2,"313":2,"315":4,"316":4,"326":4,"349":2,"357":4,"392":1,"393":2,"395":2,"396":9,"434":4,"493":6,"543":10,"544":12,"570":2,"572":1,"578":4,"599":8}}],["port",{"2":{"573":2}}],["porname",{"2":{"399":2}}],["pormiseb",{"2":{"243":2}}],["pop",{"2":{"212":2,"279":8}}],["populate",{"2":{"12":2}}],["pointer",{"2":{"113":2,"577":2}}],["possibly",{"2":{"434":2}}],["posh路径下bin目录",{"2":{"230":1}}],["poshthemes",{"2":{"223":1}}],["poshthemesget",{"2":{"223":1}}],["posh",{"2":{"222":1,"224":4,"227":4,"229":1,"230":2}}],["position",{"2":{"113":2,"179":2,"184":4,"189":4,"190":6,"195":8,"199":2,"474":8,"490":4,"551":4,"574":2,"577":4,"605":2}}],["postmessage",{"2":{"495":5,"497":1}}],["postcss",{"2":{"488":1}}],["postordertraversal",{"2":{"299":8}}],["postfile",{"2":{"15":2,"45":2,"46":8}}],["post",{"2":{"15":4,"30":6,"42":6,"43":4,"45":2,"46":4,"243":8,"589":2}}],["powershellcore",{"2":{"231":2}}],["powershell",{"2":{"231":4,"234":1}}],["power",{"2":{"107":6,"225":1}}],["pow",{"2":{"107":2,"370":4}}],["printlinkedlist",{"2":{"298":6}}],["private",{"2":{"103":6,"104":4,"105":6,"106":4,"113":12,"118":2,"125":4,"126":8,"396":6,"406":6,"407":2}}],["price",{"2":{"84":8}}],["primaryblock",{"2":{"121":6}}],["primary",{"2":{"15":2,"89":8,"90":2,"93":2,"113":4,"491":8}}],["prune",{"2":{"55":1,"205":1}}],["prerender",{"2":{"590":2}}],["preserve",{"2":{"440":4}}],["preset",{"2":{"418":2,"422":2,"423":2}}],["presets",{"2":{"418":2,"423":2}}],["preordertraversal",{"2":{"299":8}}],["preindex",{"2":{"290":23}}],["preferredauthentications",{"2":{"235":4}}],["prefix",{"2":{"46":4,"301":8,"489":1}}],["prepare",{"2":{"220":2}}],["pre",{"2":{"197":2,"326":14,"327":6,"381":8,"383":6,"385":20,"440":2,"539":14,"599":14}}],["previewlength",{"2":{"602":2}}],["previousvalue",{"2":{"378":5}}],["preventdefaultlistener",{"2":{"551":4}}],["preventdefault",{"2":{"528":1,"615":2}}],["prev",{"2":{"156":2,"298":8,"384":4}}],["prettierignore",{"2":{"357":2}}],["prettier代码格式化",{"2":{"149":1}}],["pretty",{"2":{"4":2}}],["practiceproject",{"2":{"16":2}}],["problem",{"2":{"599":2}}],["project",{"2":{"572":1}}],["production",{"2":{"570":2,"573":4}}],["product08",{"2":{"325":2}}],["product07",{"2":{"325":2}}],["product06",{"2":{"325":2}}],["product05",{"2":{"325":2}}],["product04",{"2":{"325":2}}],["product03",{"2":{"325":4}}],["product02",{"2":{"325":2}}],["product01",{"2":{"325":2}}],["pro",{"2":{"489":1}}],["proxy",{"2":{"414":2,"590":4}}],["protected",{"2":{"405":4,"406":6}}],["proto",{"2":{"274":2,"278":2,"498":1,"499":4,"500":4}}],["prototype",{"0":{"586":1},"1":{"587":1},"2":{"274":1,"276":3,"278":2,"282":8,"300":12,"318":4,"499":6,"500":5,"503":2,"527":4,"533":1,"552":1,"588":1}}],["protocol41",{"2":{"36":2}}],["province",{"2":{"318":6,"319":10}}],["provide",{"2":{"235":1,"554":1}}],["providers",{"0":{"81":1},"2":{"78":1}}],["process",{"2":{"298":2,"570":2,"573":2}}],["promistb",{"2":{"243":2}}],["promista",{"2":{"243":2}}],["promise链式调用",{"0":{"529":1}}],["promisevalue",{"2":{"525":4}}],["promise等es6特性",{"2":{"422":1}}],["promise需要改变",{"2":{"308":1}}],["promises",{"2":{"243":4,"313":12,"314":10,"315":10}}],["promisearr",{"2":{"295":12}}],["promiseall",{"2":{"295":4}}],["promisea",{"2":{"243":2}}],["promise",{"0":{"239":1,"313":1},"2":{"15":8,"146":1,"239":9,"240":2,"242":2,"243":4,"295":10,"303":14,"304":12,"305":4,"306":4,"307":10,"308":10,"309":8,"310":14,"311":30,"312":6,"313":12,"314":15,"315":58,"414":6,"493":2,"494":4,"525":8,"551":2}}],["program",{"2":{"230":2,"231":2}}],["programs",{"2":{"222":1}}],["progress",{"2":{"15":8}}],["properties",{"0":{"586":1},"1":{"587":1},"2":{"588":1}}],["property",{"2":{"432":2}}],["propertydescriptor",{"2":{"426":2}}],["propertykey",{"2":{"426":2}}],["proplugins",{"2":{"570":6}}],["proposed",{"2":{"429":1}}],["proposal",{"2":{"426":1}}],["proptypes",{"2":{"144":26}}],["props简写形式",{"2":{"144":2}}],["props",{"0":{"144":1},"2":{"141":1,"144":6,"150":1,"153":2,"551":2,"554":1}}],["packagename",{"2":{"571":4}}],["package",{"2":{"432":2,"563":2,"564":1,"573":2}}],["packages",{"2":{"414":2}}],["padend",{"2":{"530":1}}],["padding",{"2":{"185":2,"189":2,"195":2,"198":2,"201":2,"475":2,"482":1,"490":4,"491":10,"541":2,"577":2,"603":4}}],["padstart",{"2":{"46":2,"294":2,"530":1}}],["patterntransform=",{"2":{"178":2}}],["patternunits=",{"2":{"178":2}}],["pattern",{"2":{"178":8,"301":24,"578":4}}],["pathpice",{"2":{"599":10}}],["patharr",{"2":{"578":4}}],["paths",{"0":{"433":1},"2":{"433":2,"440":2}}],["pathstr",{"2":{"17":2}}],["path",{"0":{"17":1},"2":{"17":4,"22":16,"43":2,"46":6,"221":2,"230":4,"335":4,"418":8,"563":1,"564":1,"578":8,"584":2,"599":20}}],["palce",{"2":{"167":2}}],["paginationoptions",{"2":{"157":6,"158":4,"159":10}}],["page",{"2":{"157":16,"158":4,"605":2}}],["pager",{"2":{"156":2}}],["pageoptions",{"2":{"156":2,"157":2}}],["pages服务部署",{"2":{"396":1}}],["pages自带的workflow部署",{"2":{"396":1}}],["pages🎉",{"2":{"395":2}}],["pagesize",{"2":{"157":2,"158":6,"159":6}}],["pagesizes",{"2":{"156":2}}],["pages",{"2":{"42":2,"395":2,"396":13}}],["payload",{"2":{"43":2}}],["parcel也很棒",{"2":{"429":1}}],["part",{"2":{"302":4}}],["parentcomponent",{"2":{"103":2,"104":2}}],["parent",{"2":{"96":2,"103":6,"104":6,"105":1,"106":3,"180":2,"474":10,"502":4,"503":4,"504":2,"577":4}}],["parsefloat",{"2":{"509":2,"578":2}}],["parse",{"2":{"157":2,"310":10,"311":10,"315":10,"527":2}}],["parser",{"2":{"43":2}}],["parseint",{"2":{"12":4,"157":4,"373":2,"509":9}}],["params",{"2":{"12":2,"15":4,"539":18}}],["password",{"2":{"9":2,"13":2,"34":2,"42":2,"43":2,"396":6}}],["p",{"2":{"4":2,"56":4,"64":8,"84":12,"87":8,"91":12,"92":24,"95":4,"102":12,"105":4,"106":4,"114":4,"116":16,"117":12,"121":24,"122":16,"123":48,"124":12,"126":12,"133":4,"135":4,"144":10,"205":5,"270":4,"295":12,"308":4,"311":4,"314":2,"345":8,"346":8,"350":6,"406":12,"578":2,"610":8}}],["美女",{"2":{"4":4,"7":6}}],["lg",{"2":{"489":1,"586":6}}],["lmhosts",{"2":{"450":1}}],["lrth",{"2":{"396":2}}],["lrucache",{"2":{"296":4}}],["lru缓存算法",{"0":{"296":1},"2":{"296":2}}],["l=",{"2":{"122":2}}],["l",{"2":{"122":4,"207":4,"234":1,"345":2,"578":4}}],["lssh",{"2":{"234":1}}],["ls",{"2":{"55":1,"62":2,"232":1,"396":2}}],["leftmenuopen",{"2":{"584":4}}],["left",{"2":{"179":6,"189":4,"190":2,"195":6,"289":6,"299":18,"300":20,"474":4,"479":1,"490":2,"551":2,"574":2}}],["less",{"2":{"149":1,"488":1,"548":1}}],["lenarray",{"2":{"392":1,"393":4}}],["len=",{"2":{"122":2}}],["len",{"2":{"122":4,"287":6,"290":4,"292":10,"302":6,"319":6,"540":6}}],["length",{"2":{"15":6,"158":2,"159":2,"279":10,"282":2,"283":2,"287":2,"288":4,"289":6,"290":2,"291":4,"292":18,"295":8,"301":4,"302":18,"313":4,"315":4,"316":6,"318":10,"319":2,"326":2,"357":2,"375":2,"382":2,"393":4,"493":8,"494":8,"495":2,"536":4,"540":2,"543":2,"544":2,"578":2,"599":6}}],["letter",{"2":{"578":6}}],["let",{"0":{"514":1},"1":{"515":1,"516":1},"2":{"5":2,"9":2,"10":2,"11":4,"15":8,"21":2,"22":2,"36":2,"37":2,"38":4,"45":2,"46":16,"108":2,"114":8,"121":2,"122":24,"126":4,"159":8,"243":4,"258":2,"260":2,"262":4,"263":4,"268":2,"278":2,"279":18,"282":8,"283":4,"285":6,"287":8,"288":8,"289":2,"290":6,"291":8,"292":4,"295":12,"297":4,"298":20,"301":20,"302":62,"308":9,"309":4,"310":8,"311":2,"313":7,"314":6,"315":4,"316":10,"318":2,"319":11,"321":3,"322":4,"323":1,"324":16,"325":3,"326":10,"341":6,"342":2,"345":2,"346":16,"347":12,"348":4,"349":3,"350":8,"357":4,"362":2,"363":2,"381":3,"383":1,"385":5,"389":3,"393":2,"399":14,"400":11,"401":2,"402":13,"434":4,"493":2,"494":6,"499":2,"502":2,"503":2,"504":2,"510":2,"514":1,"516":2,"519":6,"520":8,"523":4,"524":4,"525":8,"527":14,"532":2,"536":2,"539":7,"540":2,"542":2,"543":14,"544":10,"577":8,"578":16,"599":32,"610":4,"614":4}}],["layer`",{"2":{"586":2}}],["layout",{"2":{"156":2,"455":1,"459":2,"465":2,"475":1,"577":2}}],["latest",{"2":{"396":2}}],["lastname",{"2":{"412":4}}],["lastres",{"2":{"302":4}}],["last",{"2":{"122":8}}],["lastindexof",{"2":{"15":2,"530":1}}],["label=",{"2":{"609":4}}],["labelstyle",{"2":{"578":12,"580":2}}],["labelcfg",{"2":{"577":4,"578":8}}],["label",{"2":{"61":2,"96":4,"123":16,"578":16,"580":4,"611":2}}],["laoqi",{"2":{"37":2}}],["lang=",{"2":{"15":4,"151":2,"152":2,"153":2,"614":2}}],["loading",{"2":{"610":12}}],["loader和plugin区别",{"0":{"548":1}}],["loader",{"2":{"417":2,"418":10,"422":2,"423":8,"548":4}}],["loaded",{"2":{"15":2}}],["lock",{"2":{"563":1}}],["localstorage",{"2":{"472":1,"522":1,"523":7}}],["locales",{"2":{"268":2}}],["local",{"2":{"61":2,"66":2,"222":1,"573":2}}],["localhost",{"2":{"15":4,"45":2,"46":9,"572":2,"592":1}}],["loop",{"2":{"525":8}}],["looseautocomplete",{"2":{"424":4}}],["lorem",{"2":{"371":4}}],["long",{"2":{"268":2}}],["lowercasepipe",{"2":{"132":1}}],["log2",{"2":{"242":2}}],["log1",{"2":{"242":2}}],["logs",{"2":{"58":2}}],["logout",{"2":{"42":2}}],["login",{"2":{"42":2,"43":2,"55":2}}],["log",{"2":{"10":2,"13":2,"15":2,"16":16,"18":4,"20":4,"21":2,"22":14,"25":8,"28":4,"29":28,"30":6,"34":4,"35":4,"36":8,"37":10,"38":8,"42":2,"43":4,"45":6,"46":2,"61":2,"93":4,"103":22,"104":6,"105":6,"106":4,"109":16,"113":2,"118":2,"121":2,"125":4,"126":4,"130":2,"139":2,"140":2,"145":4,"151":2,"152":2,"153":2,"238":10,"240":4,"241":2,"242":4,"243":6,"245":10,"246":2,"247":2,"262":8,"264":2,"265":4,"269":6,"270":2,"271":4,"272":2,"276":2,"285":2,"293":4,"295":4,"296":18,"297":8,"298":4,"299":6,"301":4,"302":2,"303":2,"307":8,"308":12,"313":4,"314":4,"316":2,"318":6,"319":10,"324":4,"330":4,"331":8,"332":6,"333":2,"340":2,"341":10,"342":4,"346":2,"362":2,"363":2,"364":6,"370":2,"372":2,"381":2,"383":2,"384":2,"385":2,"389":4,"393":2,"404":2,"406":6,"407":2,"408":4,"409":2,"410":6,"411":4,"426":4,"427":2,"493":2,"494":8,"495":2,"498":2,"502":2,"503":2,"504":2,"512":2,"524":4,"525":2,"532":20,"536":6,"539":2}}],["libs",{"2":{"433":4}}],["lib",{"0":{"431":1},"2":{"414":2,"440":2}}],["linkcenter",{"2":{"577":2}}],["link",{"2":{"456":1,"573":1,"599":6}}],["linkedlist",{"2":{"298":4}}],["linedashoffset",{"2":{"578":2}}],["linedash",{"2":{"578":2}}],["lineargradient",{"2":{"478":5}}],["linear",{"2":{"179":2,"186":8,"195":8,"198":2,"199":2,"478":2}}],["line",{"2":{"176":2,"190":2,"198":2,"474":1,"577":4,"578":8}}],["linux目录结构",{"0":{"71":1}}],["linux为",{"2":{"61":2}}],["linux",{"2":{"51":2,"66":2}}],["li",{"2":{"122":8,"144":24,"577":12}}],["light",{"2":{"99":3}}],["listpage",{"2":{"158":2}}],["list",{"2":{"96":2,"157":2,"599":6}}],["listener",{"2":{"293":8}}],["listen",{"2":{"20":2,"21":2,"22":4,"28":2,"29":4,"30":2,"42":4,"43":2,"46":2}}],["lisi",{"2":{"25":6,"399":2}}],["limit=20",{"2":{"12":2}}],["limit",{"2":{"4":2,"12":8,"55":2,"158":2}}],["likes",{"2":{"4":2,"7":8}}],["like",{"2":{"4":8,"157":2,"158":6}}],["lts",{"2":{"396":2}}],["lt",{"2":{"4":8,"5":2,"7":10,"15":36,"21":12,"22":8,"45":10,"46":10,"61":4,"84":16,"86":18,"87":8,"88":4,"89":24,"90":26,"91":12,"92":32,"93":8,"95":16,"96":18,"98":4,"102":34,"104":30,"105":40,"106":40,"107":28,"108":10,"109":1,"113":22,"114":86,"116":52,"117":20,"118":12,"119":4,"121":62,"122":40,"123":96,"124":14,"125":2,"126":28,"128":4,"129":4,"130":16,"133":4,"135":4,"137":12,"139":36,"140":7,"143":6,"144":40,"145":14,"146":4,"150":6,"151":16,"152":16,"153":16,"159":2,"168":16,"170":16,"173":8,"174":4,"178":16,"210":2,"249":2,"256":10,"260":2,"279":4,"281":2,"282":4,"285":6,"287":4,"288":8,"289":6,"290":6,"291":6,"292":16,"294":2,"295":2,"297":8,"300":8,"301":4,"302":10,"303":24,"316":6,"318":2,"319":4,"326":2,"335":12,"346":36,"347":36,"349":32,"350":16,"357":4,"362":2,"365":2,"388":1,"389":2,"393":2,"399":2,"400":2,"402":2,"424":8,"478":16,"482":20,"493":2,"494":2,"536":4,"551":18,"577":16,"586":14,"587":8,"609":18,"610":42,"614":14}}],["$bus",{"2":{"612":6}}],["$background",{"2":{"195":6}}],["$el",{"2":{"610":2}}],["$emit",{"2":{"610":4,"612":2}}],["$event",{"2":{"93":2,"96":2,"109":1,"116":2,"117":4,"125":2}}],["$message",{"2":{"610":2}}],["$host",{"2":{"590":2}}],["$remote",{"2":{"590":2}}],["$refs",{"2":{"584":2,"610":2,"615":4}}],["$router",{"2":{"157":6,"572":2}}],["$route",{"2":{"157":8,"158":2}}],["$px",{"2":{"583":8}}],["$profile",{"2":{"228":1}}],["$profilecode",{"2":{"228":1}}],["$designheight",{"2":{"583":4}}],["$designwidth",{"2":{"583":4}}],["$data",{"2":{"577":2}}],["$on",{"2":{"612":2}}],["$off",{"2":{"612":2}}],["$options",{"2":{"577":2}}],["$or",{"2":{"4":4}}],["$value",{"2":{"574":8}}],["$canvasref",{"2":{"551":10}}],["$color",{"2":{"177":2}}],["$`",{"2":{"346":2}}],["$1",{"2":{"346":2}}],["$y",{"2":{"195":6}}],["$x",{"2":{"195":6}}],["$nexttick",{"2":{"610":2}}],["$notify",{"2":{"159":4,"610":4}}],["$nginx",{"2":{"61":2}}],["$angle",{"2":{"195":10}}],["$any",{"2":{"135":2}}],["$alpha",{"2":{"177":2}}],["$attrs",{"2":{"150":1,"151":4,"152":4,"153":4}}],["$implicit",{"2":{"114":2,"122":2,"126":4}}],["$in",{"2":{"4":2}}],["$",{"0":{"342":1},"2":{"56":2,"157":2,"285":4,"294":2,"302":2,"342":2,"345":2,"346":8,"347":2,"348":2,"350":6,"396":6,"571":2,"577":6,"578":2,"599":12,"613":2,"614":2}}],["$store",{"2":{"584":2}}],["$set",{"2":{"7":8,"11":2}}],["$size",{"2":{"4":2,"195":8}}],["$lt",{"2":{"4":8}}],["o3",{"2":{"504":8}}],["o2",{"2":{"503":8}}],["o1",{"2":{"502":8}}],["omit",{"2":{"424":4}}],["o6ukw45e",{"2":{"357":2}}],["ownkeys",{"2":{"318":2}}],["oldestkey",{"2":{"296":4}}],["oldname",{"2":{"46":8}}],["oh",{"2":{"222":1,"224":2,"227":2,"229":1,"230":2}}],["ohmyposh",{"2":{"222":1}}],["ohmyposhwinget",{"2":{"222":1}}],["overflow",{"2":{"176":8,"177":4,"482":7,"610":2,"611":4}}],["other",{"2":{"123":8}}],["od=",{"2":{"122":2}}],["odd",{"2":{"122":8}}],["od",{"2":{"122":4}}],["outdiv",{"2":{"577":6}}],["outdir",{"2":{"414":4,"440":4}}],["outfile",{"2":{"414":4,"440":2}}],["outline",{"2":{"185":2,"189":2}}],["outlet组件里的value",{"2":{"114":2}}],["outlet组件里的context",{"2":{"114":2}}],["outlet组件中的数据",{"2":{"114":4}}],["outlet",{"2":{"114":14}}],["out",{"2":{"179":2}}],["output变量名=输入属性名+change",{"2":{"116":2}}],["output",{"0":{"96":1},"2":{"94":1,"96":4,"113":4,"116":8,"125":4,"418":2,"573":4}}],["observe",{"2":{"250":2,"615":2}}],["observer",{"2":{"250":6}}],["observable",{"2":{"112":1}}],["objarr1",{"2":{"319":4}}],["obj3",{"2":{"318":4}}],["obj1",{"2":{"318":46}}],["obj对象",{"2":{"274":1}}],["obj对象的原型链",{"2":{"274":1}}],["obj2",{"2":{"265":2,"318":36}}],["obj",{"2":{"157":4,"262":14,"265":2,"272":2,"274":1,"319":24,"326":6,"402":2,"512":3,"527":30}}],["object顶级对象是",{"2":{"499":2}}],["object值",{"2":{"433":1}}],["object\\t",{"2":{"399":2}}],["object对象",{"2":{"278":1}}],["object的原型没有原型",{"2":{"275":1}}],["object中的属性名只能是字符串或符号",{"2":{"265":1}}],["object中存储的数据就可以认为是一种键值对结构",{"2":{"265":1}}],["object",{"2":{"157":6,"274":1,"277":1,"316":2,"318":10,"319":2,"399":1,"414":4,"499":4,"500":1,"506":2,"507":4,"512":2,"527":4,"533":1,"552":1,"577":2,"578":2,"599":4}}],["objectid",{"2":{"6":2,"7":2,"10":2,"13":2}}],["offline",{"2":{"158":2}}],["offset=",{"2":{"478":4}}],["offset=0",{"2":{"12":2}}],["offset",{"2":{"12":4,"15":16}}],["of",{"0":{"586":1},"1":{"587":1},"2":{"108":2,"122":2,"230":4,"243":4,"263":2,"265":2,"318":2,"349":2,"357":2,"588":1}}],["o",{"2":{"66":2,"292":2,"543":2,"544":2}}],["okay",{"2":{"434":6}}],["ok",{"2":{"55":2,"400":2,"428":2,"512":2}}],["okpacket",{"2":{"36":2}}],["opath",{"2":{"578":12}}],["opacity",{"2":{"203":4,"551":2,"577":2,"578":28,"614":4}}],["opt",{"2":{"573":2}}],["optimization",{"2":{"571":2}}],["options",{"2":{"113":14,"157":4,"268":2,"418":2,"423":2,"440":2,"602":6}}],["option",{"2":{"2":2,"333":4,"334":2,"507":8}}],["operate",{"2":{"540":14}}],["opens",{"2":{"426":2,"429":1,"432":1,"438":1}}],["opensaveas",{"2":{"334":2}}],["opensave",{"2":{"334":2}}],["openshow",{"2":{"334":2}}],["opencreate",{"2":{"334":4}}],["openfilepicker",{"2":{"333":2}}],["open",{"2":{"13":2,"234":1,"333":2,"420":2,"573":2,"584":2}}],["op",{"2":{"157":8,"158":2}}],["onresize",{"2":{"584":2}}],["onrejected",{"2":{"305":8,"306":6,"307":2,"308":12,"309":2,"310":16,"311":12,"315":14}}],["ontouchstart=",{"2":{"551":2}}],["ondragstart=",{"2":{"551":2}}],["ondestroy",{"2":{"109":4,"113":2}}],["onmounted",{"2":{"614":2}}],["onmouseleave",{"2":{"125":2}}],["onmouseenter",{"2":{"125":2}}],["onmessage",{"2":{"495":6}}],["onselectdir",{"2":{"357":4}}],["onfetch",{"2":{"335":2}}],["onfulfilled",{"2":{"305":8,"306":2,"307":2,"308":12,"309":2,"310":16,"311":12,"315":14}}],["onlineispref",{"2":{"584":2}}],["online",{"2":{"158":2}}],["onload",{"2":{"15":2,"331":2,"333":2,"335":2,"551":4}}],["onpush策略会把组件从组件树中剥离出去",{"2":{"112":1}}],["onpush",{"2":{"112":1,"113":2}}],["onpushchangedetection",{"2":{"112":1}}],["onpush下触发变更检测时机",{"0":{"112":1}}],["onprogress",{"2":{"15":4}}],["oninit",{"2":{"103":4,"104":4,"105":4,"106":4,"109":4,"113":8,"114":4,"116":8,"121":4}}],["oncontextmenu",{"2":{"551":2}}],["oncontextmenu=",{"2":{"551":4}}],["onchange=",{"2":{"146":4}}],["onchanges",{"2":{"109":4,"126":4}}],["onclick=",{"2":{"143":2}}],["onclick1",{"2":{"93":6}}],["onclick",{"2":{"93":6,"528":1,"536":4}}],["once",{"2":{"13":2}}],["onbuild",{"2":{"61":2}}],["onupload",{"2":{"45":4}}],["onuploadprogress",{"2":{"15":2}}],["on",{"2":{"13":2,"20":2,"21":2,"22":4,"36":2,"293":6,"347":6,"396":4,"551":2,"577":4,"592":1,"609":2}}],["orange",{"2":{"364":6,"481":2}}],["original",{"2":{"298":2}}],["originalname",{"2":{"46":4}}],["origin",{"2":{"184":2,"195":4,"198":2,"205":2,"206":2,"207":2,"211":23,"213":2}}],["orient",{"2":{"176":2}}],["or",{"2":{"4":6,"230":4,"234":1,"440":8,"592":1}}],["or条件",{"2":{"4":1}}],["相比于位图图像",{"2":{"484":1}}],["相邻选择器",{"2":{"476":1}}],["相等",{"2":{"512":1}}],["相等与全等区别",{"0":{"512":1}}],["相等则再递归对比值是否相等",{"2":{"318":1}}],["相等运算符",{"0":{"257":1}}],["相同",{"2":{"599":2}}],["相同则不需要发请求",{"2":{"559":2}}],["相同属性名",{"2":{"554":1}}],["相同属性后定义覆盖先定义",{"2":{"476":1}}],["相同的是否收集",{"2":{"326":2}}],["相同的元素只保留一个",{"2":{"316":2}}],["相同字段and查询中出现多次",{"2":{"4":2}}],["相对定位relative",{"2":{"479":1}}],["相对单位会变成绝对单位",{"2":{"458":1}}],["相对于不同环境打包时的打包命令",{"2":{"573":1}}],["相对于最近滚动祖先定位",{"2":{"479":1}}],["相对于最近的非",{"2":{"479":1}}],["相对于浏览器视口进行定位",{"2":{"479":1}}],["相对于",{"2":{"324":2}}],["相对于原生事件监听",{"2":{"125":1}}],["相对路径在上一层读取不了文件",{"2":{"16":1}}],["相当于执行",{"2":{"563":1}}],["相当于一个标识",{"2":{"232":2}}],["相当于是在原有的提交上进行修改",{"2":{"213":2}}],["相当于用",{"2":{"113":2}}],["相当于在父组件的style中使用标签选择器选择",{"2":{"98":2}}],["相当于对父组件传入的aliasitem变量进行重命名",{"2":{"95":2}}],["相关错误",{"0":{"588":1}}],["相关的两个包",{"2":{"43":2}}],["相关概念",{"0":{"0":1}}],["男",{"2":{"4":12,"5":4,"144":6,"399":2}}],["382",{"2":{"578":2}}],["31",{"2":{"578":2}}],["311",{"2":{"578":2}}],["3s",{"2":{"578":2}}],["3左右",{"2":{"485":1}}],["364",{"2":{"578":2}}],["36",{"2":{"370":2}}],["3777dd",{"2":{"585":2}}],["370",{"2":{"578":2}}],["37",{"2":{"365":2}}],["3个",{"2":{"347":2}}],["3=3",{"2":{"296":4}}],["34|56",{"2":{"341":2}}],["34",{"2":{"285":2,"578":2}}],["359",{"2":{"578":2}}],["35",{"2":{"268":2,"578":2}}],["35px",{"2":{"189":2}}],["32px",{"2":{"603":8}}],["320",{"2":{"578":2}}],["32",{"2":{"268":2}}],["3秒后打印的",{"2":{"238":4}}],["3和",{"2":{"210":2}}],["3em",{"2":{"195":12}}],["3px",{"2":{"98":2,"191":1}}],["333",{"2":{"578":4}}],["333399",{"2":{"478":1}}],["33",{"2":{"84":2,"186":4}}],["3",{"0":{"6":1,"11":1,"22":1,"36":1,"42":1,"56":1,"68":1,"72":1,"86":1,"118":1,"234":1,"253":1,"342":1,"418":1,"428":1},"1":{"57":1,"58":1,"59":1,"60":1,"63":1,"64":1,"66":1,"67":1,"68":1},"2":{"4":2,"16":12,"36":2,"79":2,"80":2,"103":2,"104":2,"107":2,"108":4,"137":5,"140":1,"145":2,"147":17,"165":1,"168":4,"170":4,"172":8,"176":2,"177":2,"179":2,"186":4,"210":2,"243":4,"282":8,"285":2,"288":2,"296":8,"297":8,"298":2,"299":10,"302":4,"303":2,"304":2,"315":4,"316":12,"319":10,"321":4,"322":4,"324":6,"329":4,"330":4,"346":2,"347":4,"363":4,"364":10,"365":2,"370":2,"372":4,"373":4,"378":1,"380":4,"381":4,"382":4,"383":4,"385":2,"393":2,"399":4,"408":2,"418":2,"423":2,"424":2,"432":2,"448":1,"482":1,"493":4,"494":4,"495":2,"512":4,"532":8,"539":8,"540":2,"577":2,"578":12,"602":1}}],["305",{"2":{"578":2}}],["303133",{"2":{"577":2,"578":2}}],["300",{"2":{"493":2,"494":2,"577":4,"578":4}}],["3000",{"2":{"15":4,"45":2,"46":11,"238":8,"578":10}}],["30deg",{"2":{"189":2,"195":4}}],["30db",{"2":{"4":2}}],["30px",{"2":{"166":6,"186":2}}],["30s",{"2":{"43":2}}],["30",{"2":{"4":16,"37":2,"84":2,"156":2,"165":2,"262":2,"346":6,"362":4,"384":2}}],["39",{"2":{"2":12,"4":44,"5":68,"6":12,"7":40,"9":4,"10":8,"11":4,"12":20,"13":68,"15":32,"16":72,"17":16,"18":20,"20":32,"21":8,"22":28,"25":28,"28":20,"29":108,"30":52,"34":32,"35":16,"36":18,"42":60,"43":72,"45":32,"84":12,"85":16,"89":20,"90":24,"91":24,"92":64,"93":16,"95":26,"96":38,"103":72,"104":24,"105":28,"106":24,"107":8,"108":64,"109":48,"113":68,"114":24,"116":56,"117":8,"118":12,"119":8,"121":32,"122":32,"123":24,"124":12,"125":36,"126":28,"130":20,"137":4,"139":4,"140":8,"143":16,"144":32,"145":12,"146":8,"151":8,"152":8,"153":12,"156":4,"157":32,"158":4,"179":4,"189":4,"190":8,"195":8,"197":8,"213":4,"220":8,"230":4,"232":4,"239":12,"240":8,"241":4,"242":12,"243":12,"245":44,"246":4,"247":4,"249":16,"250":12,"251":4,"253":4,"256":28,"257":8,"261":4,"262":4,"265":4,"268":6,"269":4,"270":4,"279":88,"283":12,"293":24,"294":4,"295":4,"302":132,"303":20,"304":12,"305":8,"307":16,"308":4,"313":8,"315":12,"316":12,"318":100,"319":156,"325":72,"326":4,"329":16,"330":24,"331":12,"332":12,"333":24,"334":4,"335":16,"341":16,"345":44,"346":14,"347":40,"348":8,"349":12,"350":4,"357":24,"364":32,"371":16,"372":8,"374":36,"375":8,"384":12,"385":36,"393":20,"395":4,"396":8,"399":32,"400":20,"402":8,"406":24,"407":8,"409":4,"410":4,"411":8,"414":280,"418":32,"433":8,"434":20,"440":80,"495":16,"498":12,"502":4,"503":4,"504":4,"507":8,"509":4,"510":8,"512":8,"519":16,"523":36,"524":12,"525":8,"527":8,"531":8,"532":8,"533":10,"536":16,"539":4,"541":8,"542":40,"551":16,"570":8,"572":8,"573":12,"574":12,"577":48,"578":72,"584":20,"589":24,"590":8,"599":80,"610":20,"612":8,"615":4}}],["a路由组件",{"2":{"612":2}}],["aop",{"2":{"552":1}}],["a标签跳转",{"2":{"528":1}}],["ajax",{"2":{"492":1}}],["audio",{"2":{"483":1}}],["authenticated",{"2":{"235":1}}],["authentication",{"2":{"234":1}}],["author",{"2":{"12":10,"13":2}}],["autozoom",{"2":{"577":6}}],["automatic",{"2":{"234":1}}],["auto自动",{"2":{"165":1}}],["auto",{"2":{"165":2,"177":2,"190":2,"197":2,"198":2,"474":6}}],["aaa",{"2":{"432":2}}],["aaab",{"2":{"126":2}}],["a值只能为99",{"2":{"402":2}}],["average",{"2":{"382":6}}],["aids",{"2":{"327":4}}],["a∩b",{"0":{"323":1,"327":1}}],["a∪b",{"0":{"322":1,"326":1}}],["a++",{"2":{"254":2,"510":4}}],["a+b+c",{"2":{"146":2}}],["a+b",{"2":{"137":1}}],["a任务需要等到b任务执行完后才执行",{"2":{"243":2}}],["a2962a402336",{"2":{"231":2}}],["ack",{"2":{"468":3}}],["accountinfo",{"2":{"609":4}}],["account",{"2":{"589":6}}],["according",{"2":{"578":2}}],["acc",{"2":{"380":4,"382":4}}],["accept",{"2":{"333":2}}],["access",{"2":{"234":2,"235":1}}],["ac1e",{"2":{"231":2}}],["activated",{"2":{"559":5}}],["active",{"2":{"98":3}}],["action来自动化部署",{"2":{"607":1}}],["actions",{"2":{"396":6}}],["action",{"0":{"396":1},"2":{"396":6}}],["action=",{"2":{"46":2}}],["again",{"2":{"230":2}}],["age推断为number",{"2":{"401":1}}],["age推断为numberlet",{"2":{"401":1}}],["agentset",{"2":{"234":1}}],["agent",{"2":{"234":8}}],["agent中",{"0":{"234":1},"2":{"234":1}}],["age默认值为18",{"2":{"144":2}}],["age+1",{"2":{"144":2}}],["age=",{"2":{"29":6,"37":2,"144":6}}],["age",{"2":{"4":34,"5":8,"6":4,"7":14,"25":6,"29":8,"30":2,"35":4,"36":4,"37":4,"144":12,"265":4,"269":8,"270":2,"271":6,"318":6,"319":10,"399":6,"400":4,"401":2,"404":8,"405":8,"406":36,"409":8,"410":8,"412":2,"498":8,"502":4,"503":4,"504":4,"527":2}}],["amale",{"2":{"400":2}}],["amend",{"2":{"213":2}}],["amp",{"2":{"158":4,"159":4,"177":8,"195":2,"255":20,"256":4,"279":12,"282":4,"290":8,"291":4,"292":8,"297":8,"301":8,"302":12,"318":8,"324":4,"346":2,"350":2,"400":6,"420":4,"434":4,"507":4,"512":8,"519":4,"535":1,"544":8,"578":4,"599":4}}],["amd",{"2":{"149":1,"414":2,"430":2,"440":2,"549":1}}],["ababacb",{"2":{"301":3}}],["abababaababacb",{"2":{"301":3}}],["abstract",{"0":{"411":1},"2":{"411":3}}],["abs",{"2":{"297":4,"302":2,"373":2}}],["absolute",{"2":{"113":2,"179":2,"189":2,"190":4,"195":4,"474":4,"490":2,"551":2,"574":2}}],["abc",{"2":{"256":2,"316":6,"531":4}}],["about",{"2":{"21":4}}],["afterdraw",{"2":{"578":10}}],["after",{"2":{"189":2,"190":2,"490":2}}],["afterviewchecked",{"2":{"109":4}}],["afterviewinit",{"2":{"103":4,"104":4,"105":4,"106":4,"109":4,"121":4}}],["aftercontentinit",{"2":{"109":4}}],["aftercontentchecked",{"2":{"109":4}}],["affectedrows",{"2":{"36":4,"37":4,"38":4}}],["affectedrows大于0表示插入成功",{"2":{"36":2}}],["a=",{"2":{"55":2,"145":2,"325":2}}],["alwaysstrict",{"2":{"414":2,"434":1,"440":2}}],["alt",{"2":{"603":2}}],["alternate",{"2":{"203":4}}],["alt=",{"2":{"86":6,"88":2,"551":2}}],["alert标签",{"2":{"113":2}}],["alertcomponent",{"2":{"113":14}}],["alert",{"2":{"113":13,"239":8,"539":2}}],["alertoption",{"2":{"113":6}}],["alerttheme",{"2":{"113":4}}],["alive内置缓存组件",{"0":{"559":1}}],["alice",{"2":{"385":6,"498":6}}],["alias",{"2":{"126":2,"571":2}}],["aliasitem",{"2":{"95":2}}],["align",{"2":{"92":6,"167":4,"168":4,"170":2,"174":7,"474":7,"577":2,"603":2,"611":2}}],["aliyuncs",{"2":{"55":8}}],["aliyun",{"2":{"51":2}}],["allowsyntheticdefaultimports",{"2":{"440":2}}],["allowjs",{"0":{"437":1},"2":{"414":2,"440":2}}],["all组合",{"2":{"243":2}}],["allheros",{"2":{"108":4}}],["all",{"0":{"313":1},"2":{"15":2,"243":2,"313":4,"315":2,"492":2,"571":4,"577":2}}],["allprogress",{"2":{"15":6}}],["addshape",{"2":{"578":28,"580":2}}],["add1",{"2":{"540":10}}],["addtask",{"2":{"493":4}}],["addr",{"2":{"590":2}}],["addrange",{"2":{"574":2}}],["addrule",{"2":{"457":1}}],["address",{"2":{"318":6,"319":10,"399":2,"412":2}}],["added表示成功",{"2":{"234":1}}],["addeventlistener默认绑定冒泡阶段",{"2":{"528":1}}],["addeventlistener",{"2":{"125":1,"249":2,"495":6,"528":1,"551":2,"574":4,"577":2,"584":4,"610":2,"614":2,"615":2}}],["add区别",{"2":{"211":1}}],["addhero",{"2":{"108":4}}],["addnewitem",{"2":{"96":4}}],["additem",{"2":{"96":4}}],["add",{"2":{"51":2,"61":4,"96":4,"209":2,"211":6,"234":4,"266":2,"395":2,"539":22}}],["admin",{"2":{"42":2,"43":4}}],["attachview",{"2":{"113":2}}],["attrs",{"2":{"578":28,"580":2}}],["attr=",{"2":{"150":2}}],["attr=attr",{"2":{"126":2}}],["attributes",{"2":{"150":2}}],["attr",{"2":{"87":4,"102":4,"126":8,"326":6,"541":18,"578":4}}],["at",{"2":{"36":2,"42":2,"43":2,"46":2,"347":6,"530":1}}],["apache2",{"2":{"61":4}}],["apt",{"2":{"55":2,"70":1}}],["appdata",{"2":{"222":1}}],["appunless=",{"2":{"126":6}}],["appunless",{"2":{"126":8}}],["apphighlight=",{"2":{"124":2}}],["apphighlight",{"2":{"124":4,"125":6}}],["apply除了可以调用函数",{"2":{"262":1}}],["apply",{"2":{"262":6,"282":8,"375":2,"519":6,"520":6,"548":1,"577":2,"586":2}}],["apple",{"2":{"123":10,"364":6}}],["applicationref",{"2":{"112":1,"113":4}}],["appref",{"2":{"113":4}}],["appcomponent",{"2":{"82":2,"84":2,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":2,"96":2,"108":3,"109":2,"116":4,"126":2,"130":2}}],["appmodule",{"2":{"82":2}}],["app",{"2":{"28":6,"29":23,"30":10,"42":18,"43":16,"46":6,"84":2,"85":6,"89":2,"90":2,"91":2,"92":2,"93":2,"95":12,"96":8,"98":6,"102":4,"103":2,"104":14,"105":22,"106":30,"108":2,"109":6,"113":5,"114":6,"116":28,"119":4,"121":6,"122":2,"123":2,"126":2,"130":10,"414":2,"572":5,"573":4}}],["appendchild",{"2":{"113":2,"574":2}}],["append",{"2":{"15":10,"45":2}}],["api技术",{"2":{"492":1}}],["api都能用",{"2":{"125":1}}],["apirouter",{"2":{"30":8}}],["api",{"2":{"27":2,"30":2,"42":8,"43":6,"336":2,"526":2,"561":1,"589":6}}],["a",{"0":{"324":1,"328":1},"2":{"17":4,"55":2,"56":6,"75":2,"137":1,"146":3,"147":2,"161":1,"168":12,"170":12,"173":4,"197":2,"230":6,"234":1,"243":4,"251":8,"252":8,"253":4,"254":2,"255":4,"256":2,"258":4,"264":6,"284":6,"287":20,"297":8,"316":6,"319":8,"321":2,"322":2,"324":16,"327":2,"335":4,"345":2,"346":2,"348":2,"350":10,"388":13,"389":4,"395":2,"400":4,"402":2,"405":4,"432":4,"510":2,"512":21,"519":2,"524":6,"539":8,"578":2,"586":4}}],["antv",{"2":{"578":2}}],["animate",{"2":{"577":2,"578":22}}],["animation",{"2":{"179":2,"203":4}}],["animals",{"2":{"411":2}}],["animal",{"2":{"271":4,"277":1,"409":4,"410":4,"411":2}}],["an",{"2":{"96":2,"295":2}}],["angular",{"2":{"78":1,"84":4,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":4,"96":4,"103":2,"104":2,"105":2,"106":2,"107":2,"108":5,"109":3,"113":4,"114":2,"116":8,"119":2,"121":6,"122":2,"123":2,"125":2,"126":4,"128":4,"129":5,"130":4,"132":1}}],["angular基础总结一",{"0":{"76":1},"1":{"77":1,"78":1,"79":1,"80":1,"81":1,"82":1,"83":1,"84":1,"85":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"97":1,"98":1,"99":1,"100":1,"101":1}}],["any类型时报错",{"2":{"440":2}}],["any类型时是否报错",{"2":{"428":1}}],["any类型可以赋值任意类型",{"2":{"400":1}}],["any类型可以赋值任意类型let",{"2":{"400":1}}],["any\\t\\t",{"2":{"400":2}}],["any",{"2":{"15":2,"108":4,"121":4,"126":2,"333":4,"334":4,"400":2,"428":2,"440":2}}],["and",{"2":{"4":4,"230":2,"234":2,"396":4}}],["and条件",{"2":{"4":1}}],["ascii",{"2":{"531":4}}],["asfghj",{"2":{"402":2}}],["aset",{"2":{"324":4}}],["assign",{"2":{"157":6,"527":2,"577":2,"578":2,"599":2}}],["assertion",{"2":{"134":1}}],["assets",{"2":{"86":2}}],["as",{"0":{"402":1},"2":{"15":2,"113":4,"121":2,"122":4,"126":2,"230":2,"333":2,"334":4,"335":2,"400":2,"402":6}}],["asynciterable",{"2":{"414":4}}],["asyncgenerator",{"2":{"414":2}}],["async的函数并不会阻塞后续同步代码执行",{"2":{"240":2}}],["async标记该函数就是一个异步函数",{"2":{"240":1}}],["asyncpipe",{"2":{"132":1}}],["async",{"0":{"240":1},"1":{"241":1,"242":1,"243":1},"2":{"9":2,"10":2,"12":4,"15":4,"112":1,"122":4,"159":2,"240":2,"241":2,"242":2,"243":5,"333":2,"334":6,"335":2,"357":4,"493":2,"494":2,"551":4,"589":2}}],["area",{"2":{"168":6,"170":6,"173":10}}],["areas",{"2":{"168":2,"170":2}}],["around",{"2":{"167":4}}],["arrowfunction",{"2":{"418":2}}],["arr=",{"2":{"363":2,"364":2,"365":2,"370":2}}],["arr2数组没有的对象",{"2":{"328":2}}],["arr2",{"2":{"292":10,"322":18,"323":4,"324":4,"326":12,"327":8,"328":8,"364":4}}],["arr11",{"2":{"385":3}}],["arr1",{"2":{"292":10,"322":18,"323":4,"324":4,"326":12,"327":6,"328":8,"364":6,"385":2,"399":4}}],["arr数组已全部匹配",{"2":{"279":2}}],["arr",{"2":{"137":1,"146":1,"247":4,"265":4,"279":8,"282":38,"287":26,"288":25,"289":16,"290":19,"316":40,"319":6,"326":14,"360":4,"363":2,"364":6,"365":2,"368":2,"370":2,"372":4,"378":2,"380":4,"381":4,"383":8,"388":1,"389":6,"393":6,"399":4,"402":10,"428":4,"434":2,"527":6,"539":6,"599":2}}],["array可选",{"2":{"368":2}}],["array1",{"2":{"282":4}}],["array",{"2":{"15":4,"265":2,"282":18,"288":4,"291":18,"295":4,"301":2,"318":4,"319":2,"322":2,"324":2,"368":1,"375":2,"378":3,"383":2,"399":4,"414":6,"506":1,"527":6,"552":1}}],["arraybuffer",{"0":{"330":1},"2":{"15":4,"330":6,"336":1}}],["args",{"0":{"264":1},"2":{"264":4,"293":4,"519":10,"520":12,"539":14,"577":4}}],["arguments用来存储函数的实参",{"2":{"263":2}}],["arguments是一个类数组对象",{"2":{"263":2}}],["arguments是函数中又一个隐含参数",{"2":{"263":2}}],["arguments",{"0":{"263":1},"2":{"263":4,"295":2,"577":2}}],["arg变量可以传递给env",{"2":{"61":2}}],["arg",{"2":{"61":4,"512":1}}],["articleschema",{"2":{"13":4}}],["articlecount",{"2":{"12":4}}],["articlelist",{"2":{"12":6}}],["articleid",{"2":{"12":2}}],["article",{"2":{"10":2,"11":16,"12":14,"13":7}}],["axios等",{"2":{"492":1}}],["axios",{"2":{"15":8,"45":6}}],["await必须成对出现",{"2":{"240":1}}],["await关键字的后面要跟一个promise对象",{"2":{"240":1}}],["await",{"0":{"240":1},"1":{"241":1,"242":1,"243":1},"2":{"9":2,"10":2,"11":2,"12":10,"15":10,"158":2,"159":2,"240":3,"241":2,"242":2,"243":12,"330":4,"333":4,"334":20,"335":6,"357":10,"493":2,"494":2,"551":2,"589":2}}],["=str",{"2":{"578":2}}],["=href=",{"2":{"350":2}}],["=地图",{"2":{"350":2}}],["=digitmap",{"2":{"302":2}}],["=nums",{"2":{"362":2}}],["=n",{"2":{"285":2}}],["=10",{"2":{"285":2}}],["=1",{"2":{"285":2}}],["=\\t",{"2":{"256":2,"257":2}}],["=\\t\\t",{"2":{"252":2}}],["==0",{"2":{"363":2}}],["==",{"2":{"42":4,"43":4,"61":4,"147":4,"172":4,"220":2,"257":8,"279":12,"295":2,"298":4,"300":4,"301":4,"302":2,"304":4,"305":8,"306":4,"307":4,"308":6,"309":4,"310":6,"311":8,"313":2,"315":14,"316":2,"318":6,"319":2,"326":2,"327":2,"328":2,"347":6,"365":6,"449":5,"450":3,"500":2,"507":2,"512":19,"519":4,"527":2,"536":2,"544":2,"599":2}}],["===index",{"2":{"364":2}}],["=====",{"2":{"147":10}}],["===",{"2":{"15":4,"21":6,"22":6,"43":2,"75":2,"89":2,"121":4,"157":2,"159":2,"257":4,"279":20,"281":2,"283":2,"284":2,"292":4,"295":2,"297":2,"300":14,"301":6,"302":6,"316":8,"318":26,"319":6,"322":2,"326":4,"328":2,"331":2,"357":4,"364":2,"396":5,"400":2,"428":4,"434":2,"493":2,"494":6,"499":4,"507":4,"512":3,"519":2,"527":6,"540":4,"570":2,"573":2,"577":8,"578":4,"610":4}}],["=user",{"2":{"12":2}}],["=async",{"2":{"11":2}}],["=0",{"2":{"5":2}}],["=",{"2":{"4":10,"9":8,"10":8,"11":8,"12":24,"13":34,"15":92,"16":2,"17":4,"18":2,"20":8,"21":16,"22":40,"25":12,"28":8,"29":42,"30":20,"34":6,"35":4,"36":10,"37":10,"38":12,"42":16,"43":20,"45":10,"46":40,"84":4,"86":4,"87":4,"89":16,"90":18,"91":10,"92":18,"93":4,"95":4,"96":10,"104":2,"107":4,"108":18,"109":1,"113":26,"114":14,"116":32,"117":16,"118":14,"121":18,"122":18,"123":14,"124":4,"125":4,"126":28,"130":8,"137":2,"143":10,"144":16,"145":24,"146":16,"157":46,"158":24,"159":20,"211":22,"220":2,"238":10,"239":18,"240":2,"243":14,"245":2,"246":8,"247":18,"249":10,"250":16,"251":10,"252":12,"253":4,"256":2,"258":2,"260":2,"262":8,"263":2,"264":2,"265":14,"268":8,"269":8,"270":8,"271":6,"274":1,"276":4,"278":6,"279":26,"281":2,"282":22,"283":6,"285":4,"287":26,"288":24,"289":14,"290":16,"291":22,"292":24,"293":14,"294":14,"295":44,"296":18,"297":6,"298":44,"299":26,"300":56,"301":32,"302":76,"303":22,"304":18,"305":8,"306":4,"307":26,"308":42,"309":8,"310":30,"311":28,"312":4,"313":24,"314":26,"315":72,"316":48,"318":18,"319":16,"321":4,"322":22,"323":6,"324":26,"326":38,"327":20,"328":16,"329":4,"330":8,"331":6,"332":2,"333":16,"334":34,"335":22,"340":2,"341":6,"342":4,"345":4,"346":20,"347":12,"348":10,"349":4,"350":14,"357":22,"362":4,"363":2,"364":10,"365":6,"370":2,"371":8,"372":6,"373":6,"374":12,"375":2,"378":2,"380":6,"381":6,"382":6,"383":8,"384":6,"385":16,"388":1,"389":2,"393":8,"399":24,"400":18,"401":2,"402":16,"404":6,"405":8,"406":30,"407":8,"408":2,"409":6,"410":6,"418":8,"424":10,"428":4,"434":10,"475":2,"489":1,"493":32,"494":38,"495":8,"498":6,"499":2,"502":6,"503":8,"504":6,"507":4,"510":4,"512":10,"519":28,"520":22,"523":10,"524":8,"525":14,"526":1,"527":16,"532":4,"536":22,"539":48,"540":26,"541":4,"542":2,"543":28,"544":20,"551":36,"570":4,"571":2,"572":4,"573":2,"574":24,"577":46,"578":118,"579":4,"584":12,"589":2,"599":76,"602":2,"610":28,"614":14,"615":10}}],["0px",{"2":{"605":1}}],["09",{"2":{"578":2}}],["0性能提升",{"0":{"561":1}}],["0个或1个",{"2":{"347":2}}],["0个或多个",{"2":{"347":2}}],["08",{"2":{"325":2,"346":6}}],["07",{"2":{"325":2}}],["0\\t",{"2":{"282":2}}],["00",{"2":{"614":2}}],["009cc9",{"2":{"585":2}}],["00f",{"2":{"478":2}}],["0085f9",{"2":{"177":2}}],["000",{"2":{"168":2,"170":2,"192":2,"200":4}}],["000000",{"2":{"42":2,"43":2,"177":2}}],["06",{"2":{"43":2,"325":2}}],["05em",{"2":{"199":4}}],["05",{"2":{"43":2,"325":2}}],["03",{"2":{"43":2,"325":4}}],["04",{"2":{"43":2,"325":2}}],["024",{"2":{"578":2}}],["020",{"2":{"340":2,"342":2}}],["02",{"2":{"43":2,"318":6,"319":10,"325":2,"533":2}}],["012",{"2":{"578":2}}],["01234",{"2":{"536":2}}],["010|020",{"2":{"340":2,"342":4}}],["01",{"2":{"43":2,"325":2}}],["0",{"2":{"4":6,"13":2,"15":8,"20":4,"30":4,"34":4,"36":8,"37":4,"38":4,"42":10,"43":4,"45":2,"46":4,"84":4,"89":2,"108":2,"113":2,"157":2,"158":2,"159":2,"178":18,"179":6,"183":14,"185":6,"186":16,"188":12,"189":8,"190":8,"191":3,"192":4,"195":40,"198":4,"199":6,"203":8,"231":2,"247":2,"255":2,"260":2,"263":2,"264":2,"267":4,"279":10,"281":2,"282":2,"283":4,"284":2,"285":4,"287":4,"288":4,"289":4,"290":4,"291":4,"292":12,"293":2,"294":2,"295":4,"297":20,"301":12,"302":28,"316":6,"318":2,"319":2,"326":2,"332":10,"346":2,"347":4,"348":4,"357":2,"365":2,"378":2,"380":2,"382":2,"383":4,"384":2,"388":3,"389":2,"393":2,"396":6,"457":1,"474":8,"476":1,"478":12,"490":10,"493":6,"494":8,"495":2,"507":2,"509":2,"511":2,"512":8,"520":2,"532":5,"536":4,"539":2,"540":4,"544":4,"551":10,"571":4,"577":2,"578":84,"580":2,"585":12,"599":8,"603":10,"613":2}}],["icon",{"2":{"577":6,"610":8}}],["iconfontcpe",{"2":{"578":2}}],["iconfonthub",{"2":{"578":2}}],["iconfont",{"2":{"577":6,"578":6}}],["iconprops",{"2":{"424":8}}],["ig",{"2":{"345":2}}],["ie",{"2":{"177":2,"194":1,"418":2,"423":2}}],["i=0",{"2":{"285":2}}],["i=2",{"2":{"285":2}}],["i=",{"2":{"122":2}}],["ipad",{"2":{"489":3}}],["ipconfig",{"2":{"450":1}}],["ipsum",{"2":{"371":4}}],["ip",{"2":{"64":2,"450":1,"451":1,"452":1,"590":3}}],["iterator底层实现机制",{"2":{"506":1}}],["iterable",{"2":{"414":6,"431":2}}],["item4",{"2":{"96":2}}],["item3",{"2":{"96":2}}],["item2",{"2":{"96":2}}],["item1",{"2":{"96":2}}],["items",{"2":{"96":4,"168":10,"174":2,"474":4,"586":4,"587":4,"599":6,"603":2}}],["item变量只可以在本组件使用",{"2":{"95":2}}],["item=",{"2":{"95":2}}],["item",{"2":{"15":4,"95":10,"96":2,"108":4,"122":12,"135":2,"157":4,"168":8,"170":8,"173":2,"174":2,"243":2,"247":4,"282":8,"302":4,"316":24,"318":4,"326":8,"327":12,"385":8,"428":8,"482":6,"493":4,"494":4,"543":6,"578":20,"579":4,"599":40,"609":8}}],["it",{"2":{"55":2,"56":4,"57":2,"59":2,"349":6,"432":2,"586":2,"601":2}}],["io",{"2":{"51":2}}],["isarticledir",{"2":{"599":6}}],["isarray",{"2":{"282":2,"288":2,"295":2,"318":4,"319":2,"383":2,"527":2}}],["isobj",{"2":{"507":2}}],["isobject",{"2":{"316":4}}],["isolatedmodules",{"2":{"440":2}}],["isediting",{"2":{"610":10}}],["isexist",{"2":{"326":4}}],["isequal",{"2":{"318":16,"319":2}}],["isechocond",{"2":{"157":2}}],["isdirectory",{"2":{"599":2}}],["isdisabled均为变量",{"2":{"86":2}}],["isdisabled",{"2":{"86":2}}],["isduplicate",{"2":{"316":6}}],["ismatched",{"2":{"279":2}}],["isvalid",{"2":{"279":2}}],["isintersecting",{"2":{"250":2}}],["isrequired",{"2":{"144":6}}],["ishot",{"2":{"143":14}}],["issues",{"2":{"594":1}}],["issuccess",{"2":{"89":4}}],["isshow",{"2":{"121":14}}],["isnan",{"2":{"107":2,"519":2}}],["is",{"2":{"46":2,"55":2,"230":4,"288":2,"434":2,"519":2,"586":4}}],["islogin",{"2":{"42":4}}],["istr",{"2":{"36":8}}],["immediate=false",{"2":{"519":2}}],["immediate",{"2":{"158":2,"519":10}}],["implements",{"2":{"103":2,"104":2,"105":2,"106":2,"107":2,"108":2,"109":2,"113":4,"114":2,"116":4,"121":2,"126":2}}],["important",{"2":{"603":4,"605":2}}],["important权重最高",{"2":{"476":1}}],["importhelpers",{"2":{"440":2}}],["importscripts",{"2":{"414":2}}],["imports",{"0":{"80":1},"2":{"78":1}}],["import",{"2":{"15":4,"45":2,"59":2,"84":1,"85":1,"89":1,"90":1,"91":1,"92":1,"93":1,"95":2,"96":2,"103":3,"104":3,"105":3,"106":3,"107":1,"108":2,"109":1,"113":4,"114":1,"116":4,"119":1,"121":2,"122":1,"123":1,"125":1,"126":2,"130":2,"157":1,"433":4,"574":2,"577":1,"578":2,"602":6,"614":2}}],["img",{"2":{"86":6,"88":2,"193":1,"249":2,"250":10,"335":2,"374":6,"483":1,"551":24}}],["imgfile",{"2":{"46":2}}],["imagetocanvas",{"2":{"551":4}}],["imagetop",{"2":{"249":4}}],["image2",{"2":{"374":4}}],["image1",{"2":{"374":6}}],["imageid",{"2":{"55":2}}],["images",{"2":{"55":2,"86":2,"249":4,"250":4,"374":4}}],["image",{"2":{"13":2,"55":2,"198":2,"249":8,"250":4,"333":2,"335":2,"551":10}}],["inline",{"2":{"551":2}}],["inlinesources",{"2":{"440":2}}],["inlinesourcemap",{"2":{"440":4}}],["innerhtml",{"2":{"350":2,"577":2}}],["innerheight",{"2":{"249":2}}],["inordertraversal",{"2":{"299":8}}],["invalid",{"0":{"592":1},"1":{"593":1,"594":1},"2":{"592":1}}],["invoke",{"2":{"224":2,"227":2}}],["inventories",{"2":{"158":4}}],["inherit",{"2":{"195":4}}],["inheritattrs",{"0":{"150":1},"1":{"151":1,"152":1,"153":1},"2":{"151":2,"152":2,"153":2}}],["infinity",{"2":{"282":2,"322":2,"571":2}}],["infinite",{"2":{"179":2,"203":4}}],["info",{"2":{"90":2,"237":1}}],["in",{"0":{"277":1},"2":{"179":2,"277":1,"319":2,"385":2,"433":2,"488":1,"527":2,"599":4}}],["initevent",{"2":{"584":2}}],["initevent方法已经过时",{"2":{"584":2}}],["initchart",{"2":{"577":4}}],["initial",{"2":{"571":2}}],["initialvalue",{"2":{"378":5}}],["init",{"2":{"224":2,"227":2,"395":2,"416":1,"418":2}}],["init后才能初始化",{"0":{"219":1}}],["initsearchfromcond",{"2":{"157":2}}],["initpage",{"2":{"157":2,"158":2}}],["include处",{"2":{"491":1}}],["include和exclude",{"0":{"439":1}}],["includeduplicates",{"2":{"374":4}}],["included",{"2":{"230":2}}],["include",{"2":{"195":2,"414":6,"439":2,"440":2,"491":4}}],["includes",{"2":{"157":2,"316":6,"322":2,"323":2,"324":10,"327":2,"357":2,"381":2,"530":1,"599":2}}],["inc",{"2":{"116":8,"130":4}}],["inject",{"2":{"113":4,"554":1}}],["injector",{"2":{"113":4}}],["intl",{"2":{"414":8}}],["intersection",{"2":{"323":2,"327":4}}],["intersectionobserver",{"2":{"250":2}}],["interval",{"2":{"109":2}}],["interface",{"2":{"108":2,"113":2,"412":2,"424":8}}],["int",{"2":{"72":1}}],["into",{"2":{"36":4}}],["instanceof",{"0":{"277":1},"2":{"277":1,"282":4,"295":2,"309":4,"310":6,"311":2,"312":2,"315":4,"316":4,"318":4,"499":2,"525":2}}],["instance",{"2":{"103":8,"113":6}}],["install",{"2":{"51":4,"55":2,"70":2,"220":2,"221":2,"222":2,"570":1}}],["inspect",{"2":{"58":2,"62":4}}],["insertnode",{"2":{"300":8}}],["insertsort",{"2":{"290":2}}],["insertid",{"2":{"36":2}}],["insertmany",{"2":{"5":4}}],["insertone",{"2":{"5":2}}],["insert",{"2":{"2":2,"5":8,"300":4}}],["inputref",{"2":{"610":4}}],["input2",{"2":{"145":6}}],["input1",{"2":{"145":4}}],["inputval=",{"2":{"117":6}}],["inputval",{"2":{"117":14,"610":12}}],["input双向绑定",{"0":{"117":1}}],["input引用发生变化",{"2":{"112":1}}],["input的name属性值为imgfile和upload",{"2":{"46":2}}],["input",{"0":{"95":1},"2":{"45":2,"46":2,"94":1,"95":6,"96":4,"107":4,"108":2,"109":4,"114":4,"116":8,"117":8,"118":8,"123":8,"125":6,"126":4,"130":4,"145":8,"146":4,"483":1,"610":4}}],["index+0",{"2":{"578":2}}],["index++",{"2":{"15":2,"494":2}}],["indexeddb",{"2":{"523":1}}],["index可选",{"2":{"368":2}}],["indexof",{"2":{"316":6,"322":2,"364":4,"530":1}}],["index",{"2":{"13":1,"15":18,"21":2,"22":10,"30":2,"46":5,"78":1,"122":8,"189":4,"190":4,"301":8,"302":2,"313":2,"315":2,"316":4,"318":4,"360":4,"364":6,"368":2,"378":3,"418":4,"432":6,"433":4,"479":1,"494":6,"551":2,"578":10,"599":12,"602":1}}],["if=",{"2":{"610":4}}],["iframe",{"2":{"335":4}}],["if只会控制紧随其后的一条语句",{"2":{"259":2}}],["ifcomponent",{"2":{"121":2}}],["ifcomp",{"2":{"121":4}}],["ifcfg",{"2":{"75":2}}],["if",{"0":{"244":1},"1":{"245":1,"246":1,"247":1},"2":{"12":8,"15":6,"16":4,"18":2,"21":4,"22":10,"34":2,"35":2,"36":6,"37":8,"38":8,"42":4,"43":4,"46":2,"108":2,"113":2,"121":6,"126":8,"129":3,"137":2,"159":2,"230":2,"245":8,"246":2,"247":2,"249":2,"250":2,"259":5,"279":14,"281":4,"282":2,"283":2,"284":2,"285":2,"287":2,"288":4,"289":2,"292":6,"293":4,"295":8,"296":6,"297":8,"299":6,"300":26,"301":6,"302":12,"304":4,"305":8,"306":3,"307":4,"308":10,"309":7,"310":16,"311":14,"312":2,"313":2,"315":22,"316":12,"318":20,"319":10,"326":4,"334":2,"357":6,"365":2,"385":2,"389":4,"400":2,"432":2,"493":2,"494":6,"495":2,"512":2,"519":10,"520":6,"525":4,"527":8,"540":4,"541":4,"543":6,"544":2,"570":2,"574":4,"577":14,"578":26,"584":4,"586":2,"599":10,"610":4,"614":2}}],["i++",{"2":{"5":2,"15":2,"260":2,"279":4,"282":2,"285":4,"287":2,"288":4,"289":2,"290":2,"291":2,"292":6,"295":2,"297":2,"301":4,"302":6,"316":4,"318":2,"319":2,"326":2,"365":2,"393":2,"493":2,"494":2,"536":4,"544":2}}],["i",{"2":{"5":6,"15":12,"34":1,"56":2,"113":4,"122":4,"157":4,"210":6,"214":2,"220":2,"243":2,"260":4,"279":20,"282":10,"283":8,"285":14,"287":6,"288":18,"289":10,"290":8,"291":8,"292":20,"295":14,"297":4,"301":20,"302":22,"316":18,"318":8,"319":8,"326":8,"328":8,"345":2,"346":2,"348":2,"350":6,"365":6,"371":4,"373":4,"393":6,"400":2,"417":2,"418":8,"422":1,"493":4,"494":12,"512":6,"536":18,"544":2,"563":2,"578":12,"601":2}}],["id选择器",{"2":{"476":1}}],["identityfile",{"2":{"235":4}}],["id值不变不刷新",{"2":{"122":2}}],["id\\t",{"2":{"122":2}}],["id=",{"2":{"37":4,"38":2,"46":2,"123":8,"137":4,"139":2,"178":2,"478":2}}],["id",{"2":{"4":4,"5":2,"6":2,"7":2,"10":6,"11":6,"12":2,"35":4,"36":4,"37":6,"38":6,"108":16,"122":6,"233":1,"234":2,"235":4,"325":18,"326":16,"327":8,"328":8,"357":8,"542":10,"543":4,"544":4,"559":2,"578":4,"609":4,"610":8}}],["fcuntion",{"2":{"499":2}}],["f00",{"2":{"478":2}}],["ffcf8b",{"2":{"578":2}}],["ff00cc",{"2":{"478":1}}],["fff",{"2":{"190":2,"200":4,"577":4,"585":2}}],["ftnext",{"2":{"396":2}}],["ftype",{"2":{"357":10}}],["fdkafad",{"2":{"348":2}}],["fh",{"2":{"334":8}}],["funtion",{"2":{"520":2}}],["funcs",{"2":{"540":8}}],["funciton",{"2":{"519":2}}],["func",{"2":{"144":2,"318":6,"319":10,"519":16,"520":12,"536":4,"540":4}}],["function关键字与函数名之间有一个星号",{"2":{"524":1}}],["function",{"2":{"13":2,"16":4,"18":2,"42":2,"43":6,"137":1,"144":1,"146":1,"230":2,"239":7,"240":4,"242":2,"245":4,"246":1,"247":1,"262":2,"263":2,"264":4,"269":2,"272":1,"278":1,"279":4,"281":2,"282":10,"283":6,"284":1,"285":4,"287":1,"289":1,"290":1,"291":1,"292":5,"294":1,"295":1,"297":4,"298":3,"299":6,"300":20,"301":2,"302":6,"305":4,"308":4,"310":4,"311":4,"315":4,"318":12,"319":12,"360":2,"363":2,"368":2,"370":1,"375":2,"378":2,"388":1,"389":4,"393":2,"399":4,"412":2,"426":3,"493":2,"494":4,"495":12,"498":1,"499":2,"500":2,"503":3,"504":4,"506":1,"507":3,"519":9,"520":10,"525":11,"527":4,"528":1,"536":13,"539":12,"540":4,"541":7,"543":2,"544":4,"551":8,"574":4,"577":4,"578":12,"583":4,"584":4,"589":2,"599":8}}],["fulfilled",{"2":{"303":2,"304":2,"307":2,"308":2,"309":2,"310":2,"311":2,"315":6}}],["fufilled",{"2":{"303":4,"304":4,"305":2,"306":2,"315":2}}],["fn3",{"2":{"262":2,"264":2}}],["fn",{"2":{"243":6,"262":13,"371":4,"392":3,"393":4,"525":4,"536":8,"577":4}}],["fn2执行",{"2":{"240":2,"241":2}}],["fn2",{"2":{"240":2,"241":2,"262":7}}],["fn1执行结果",{"2":{"240":2}}],["fn1",{"2":{"240":4,"241":2,"243":4}}],["f更新远程代码",{"2":{"217":1}}],["fxzer",{"2":{"211":22,"395":2,"396":12}}],["fxj",{"2":{"55":2}}],["features",{"2":{"429":1}}],["fetch",{"2":{"205":6,"211":6,"243":8,"335":2,"396":2}}],["fext",{"2":{"17":2}}],["fb3",{"2":{"186":10}}],["flag",{"2":{"282":4,"520":8}}],["flatplus",{"2":{"282":6}}],["flat",{"2":{"282":6}}],["flatten",{"2":{"282":6}}],["fly",{"2":{"276":2}}],["floor",{"2":{"267":2,"288":2,"289":2,"291":4,"292":4,"302":2}}],["flexsearchindexoptions",{"2":{"602":4}}],["flexsearch",{"2":{"601":2,"602":2}}],["flex布局",{"2":{"474":1}}],["flex布局子元素给了高度",{"0":{"180":1}}],["flex",{"2":{"180":6,"202":6,"474":5,"482":4,"586":4,"587":4,"603":4}}],["flier",{"2":{"108":4}}],["fr",{"2":{"335":6}}],["fr片段划分",{"2":{"165":1}}],["fruit",{"2":{"123":26}}],["fromcharcode",{"2":{"530":1,"531":2}}],["from",{"2":{"4":4,"15":4,"35":2,"38":2,"45":2,"61":4,"84":2,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":4,"96":4,"103":4,"104":4,"105":4,"106":4,"107":2,"108":4,"109":2,"113":6,"114":2,"116":8,"119":2,"121":6,"122":2,"123":2,"125":2,"126":4,"130":4,"157":2,"179":2,"234":2,"265":2,"322":2,"324":2,"432":3,"433":4,"574":2,"578":2,"602":6,"614":2}}],["f=",{"2":{"122":2}}],["f60",{"2":{"91":2}}],["focus",{"2":{"610":2}}],["foo",{"2":{"434":16}}],["footer",{"2":{"105":4,"201":1}}],["folded",{"2":{"195":4}}],["fontfamily",{"2":{"578":6}}],["font终端字体",{"2":{"230":1}}],["fontsize",{"2":{"577":2,"578":14}}],["fontsizepx",{"2":{"116":18}}],["fonts字体",{"2":{"225":1}}],["font",{"2":{"116":8,"190":2,"198":2,"230":1,"231":4,"577":2}}],["found",{"2":{"21":2,"22":4}}],["for循环",{"2":{"297":2}}],["fork后的仓库",{"0":{"209":1},"2":{"211":1}}],["foreach等回调函数默认指向window",{"2":{"517":1}}],["foreach",{"2":{"157":6,"243":2,"249":2,"250":4,"265":2,"293":2,"295":2,"313":2,"315":2,"493":2,"543":6,"544":2,"578":8,"579":2,"584":4,"599":6}}],["for=",{"2":{"123":8}}],["forcomponent",{"2":{"122":2}}],["form",{"2":{"15":12,"45":2,"46":6,"118":4,"431":1}}],["formdata",{"2":{"15":8,"45":12}}],["for",{"2":{"5":1,"15":2,"119":2,"122":2,"137":2,"243":4,"260":4,"263":2,"265":2,"279":4,"282":2,"283":2,"285":4,"287":4,"288":6,"289":2,"290":2,"291":4,"295":2,"297":2,"301":4,"302":8,"311":2,"315":2,"316":6,"318":4,"319":6,"326":2,"349":2,"357":2,"365":2,"392":1,"393":2,"493":2,"494":2,"527":2,"536":4,"599":4}}],["f",{"2":{"18":2,"55":3,"56":4,"122":4,"285":10,"395":2,"400":10,"426":8,"586":14,"587":10}}],["fpath",{"2":{"17":2,"22":18}}],["fs",{"2":{"16":8,"18":8,"22":12,"46":8,"599":16}}],["fangda",{"2":{"577":2}}],["fanxj",{"2":{"55":6}}],["fallthrough",{"2":{"440":2}}],["falsy",{"2":{"255":2}}],["false\\t",{"2":{"610":2}}],["false\\t\\t",{"2":{"255":2,"256":2}}],["false==",{"2":{"257":1}}],["false",{"2":{"13":2,"30":2,"42":4,"43":2,"108":10,"121":4,"126":8,"134":1,"143":2,"150":2,"157":6,"158":2,"159":2,"231":2,"251":2,"255":2,"257":3,"279":14,"300":4,"302":2,"316":2,"318":15,"331":2,"341":4,"342":4,"346":2,"348":2,"359":1,"365":4,"374":4,"396":2,"414":2,"418":2,"426":1,"427":1,"428":1,"434":1,"435":1,"436":1,"437":1,"440":2,"509":1,"512":11,"519":2,"520":2,"551":6,"577":8,"584":2,"585":2,"589":2,"599":4,"609":2,"610":12}}],["fat",{"2":{"347":12}}],["fatal",{"2":{"234":2}}],["face",{"2":{"231":2}}],["factorial",{"2":{"281":4}}],["factory",{"2":{"113":4}}],["factor",{"2":{"107":6}}],["family",{"2":{"198":2}}],["fasle",{"2":{"152":2,"153":2}}],["failupdate",{"2":{"610":2}}],["failed",{"2":{"551":2}}],["fail",{"2":{"42":2,"239":2}}],["favoritescount",{"2":{"13":2}}],["favorited",{"2":{"12":2}}],["fittingstring",{"2":{"578":2}}],["fitviewpadding",{"2":{"577":2}}],["fitview",{"2":{"577":2}}],["fitscreen24",{"2":{"577":2}}],["fibonacci",{"2":{"281":7,"285":10}}],["fin",{"2":{"468":1}}],["finally",{"2":{"239":2,"493":2,"494":2}}],["findmediansortedarrays",{"2":{"292":4}}],["findindex",{"2":{"15":2,"326":4,"327":2}}],["findbyid",{"2":{"12":2}}],["findbyidandupdate",{"2":{"11":2}}],["findbyidandremove",{"2":{"10":2}}],["findone",{"2":{"4":4,"12":2}}],["find",{"2":{"4":36,"12":4,"247":2,"428":4,"434":2}}],["fireevent",{"2":{"584":2}}],["firefox",{"2":{"177":4,"194":1}}],["firstname",{"2":{"412":4}}],["first",{"2":{"122":8,"197":1}}],["firsttpl模板引用赋值给elseblocks变量",{"2":{"121":2}}],["firsttpl",{"2":{"121":4}}],["fixed",{"2":{"113":2,"482":1,"605":2}}],["fieldcount",{"2":{"36":2}}],["fill=",{"2":{"178":4,"478":2}}],["fill",{"2":{"165":1,"301":2,"577":4,"578":26}}],["filehandle",{"2":{"333":4,"334":10}}],["filepicker",{"0":{"333":1},"2":{"334":1}}],["filearraybuffer",{"2":{"330":6,"331":2}}],["filesteam",{"2":{"334":12}}],["files",{"0":{"439":1},"2":{"45":2,"231":2,"414":2,"440":2}}],["filereader",{"0":{"331":1},"2":{"15":2,"331":8,"333":8,"335":4,"336":1}}],["filename就是上传文件的文件名",{"2":{"46":2}}],["filename",{"2":{"15":2,"45":4,"46":10,"418":2}}],["file",{"0":{"329":1,"592":1},"1":{"593":1,"594":1},"2":{"15":34,"45":2,"46":14,"230":2,"234":1,"329":4,"330":6,"331":2,"333":6,"334":4,"335":2,"336":2,"357":6,"592":2}}],["filters",{"2":{"554":1}}],["filterarr",{"2":{"364":4}}],["filter",{"2":{"12":10,"108":2,"193":2,"316":2,"322":4,"323":2,"324":8,"327":2,"328":4,"360":2,"362":2,"363":2,"364":4,"365":2,"479":2,"599":6}}],["square",{"2":{"490":2}}],["sqrt",{"2":{"365":2}}],["sm",{"2":{"424":18,"489":1}}],["sdfj",{"2":{"400":2}}],["sync",{"2":{"396":5}}],["symbol无法转换为数宇",{"2":{"509":1}}],["symbol应用",{"2":{"506":1}}],["symbol",{"2":{"261":4,"265":2,"318":4,"414":10,"506":1,"509":1,"512":5,"539":2}}],["systype",{"2":{"577":2}}],["system32",{"2":{"450":1}}],["systemjs等",{"2":{"430":1}}],["system",{"2":{"54":2,"414":2,"430":1,"440":2}}],["systemctl",{"2":{"51":2,"72":2,"75":2}}],["sys",{"2":{"440":2}}],["sysconfig",{"2":{"75":2}}],["ssh公钥私钥加密解密原理",{"0":{"236":1}}],["ssh",{"2":{"234":8,"235":8,"396":2}}],["skewx",{"2":{"189":2}}],["skip",{"2":{"4":2,"12":4}}],["svg也具有更好的可访问性和seo性能",{"2":{"484":1}}],["svg",{"2":{"178":5,"478":5}}],["sat",{"2":{"347":6}}],["saturate",{"2":{"193":2}}],["sayhello",{"2":{"269":4,"270":2,"271":6,"272":6,"404":2,"406":6}}],["safari",{"2":{"177":2}}],["sass",{"0":{"491":1},"2":{"149":1,"548":1}}],["saveformdata",{"2":{"146":8}}],["saveinput",{"2":{"145":4}}],["saveuninitialized",{"2":{"42":2}}],["save",{"2":{"9":2}}],["switchtoedit",{"2":{"610":2}}],["switchcomponent",{"2":{"123":2}}],["switch",{"2":{"123":2,"137":2,"259":2,"440":4}}],["sbindcomponent",{"2":{"116":4}}],["sbind",{"2":{"116":24,"130":4}}],["soucemaps",{"2":{"440":2}}],["sougou",{"2":{"346":4}}],["sourceroot",{"2":{"440":2}}],["sourcemaps",{"2":{"440":4}}],["sourcemap",{"2":{"440":4}}],["source",{"2":{"231":2,"396":2,"440":2}}],["some",{"2":{"282":4,"328":2}}],["someasyncopt",{"2":{"243":10}}],["somecondition",{"2":{"129":2}}],["solid",{"2":{"91":4,"92":6,"98":2,"185":2,"190":4,"457":1,"482":4,"603":2}}],["sortby=",{"2":{"389":2}}],["sortby\\t可选",{"2":{"388":2}}],["sortby",{"2":{"12":4,"388":2,"389":2}}],["sort",{"0":{"386":1},"1":{"387":1,"388":1,"389":1},"2":{"4":2,"12":2,"387":1,"388":4,"389":4,"578":4}}],["sl",{"2":{"66":2}}],["slicepipe",{"2":{"132":1}}],["slice",{"0":{"532":1},"2":{"15":12,"108":2,"283":2,"292":4,"302":4,"527":4,"530":1,"532":12,"599":2,"614":2}}],["src属性多了个",{"0":{"593":1}}],["srclist",{"2":{"374":6}}],["src赋值给src",{"2":{"249":1}}],["src=",{"2":{"86":4,"88":2,"139":6,"303":2,"335":4,"551":6}}],["src",{"2":{"61":2,"86":2,"249":8,"250":8,"374":2,"414":4,"418":4,"432":20,"433":9,"439":2,"440":2,"551":2,"571":2}}],["s",{"2":{"56":2,"73":2,"95":2,"96":2,"121":8,"210":1,"302":4,"307":2,"344":4,"346":8,"347":8,"349":4,"586":6,"587":4}}],["sitemap",{"2":{"590":3}}],["sitemap插件使用问题",{"0":{"590":1}}],["simple",{"0":{"590":1}}],["simplechanges",{"2":{"109":4,"126":4}}],["sidebarpath",{"2":{"599":6}}],["sidebarlist",{"2":{"599":10}}],["sidebarstr",{"2":{"599":4}}],["sidebars",{"2":{"599":6}}],["sidebarobj",{"2":{"599":14}}],["sidebar",{"2":{"584":2,"599":24}}],["sizing改变其计算方式",{"2":{"475":1}}],["sizing",{"2":{"475":2}}],["sizes",{"2":{"156":2}}],["sizer",{"2":{"130":4}}],["sizechange",{"2":{"116":6,"158":2}}],["size+1",{"2":{"116":4}}],["size=16",{"2":{"116":4}}],["size",{"2":{"15":10,"116":24,"130":10,"157":10,"158":4,"186":6,"190":2,"198":2,"199":2,"265":2,"266":2,"296":2,"357":8,"424":32,"577":2,"578":14}}],["sin",{"2":{"195":2}}],["single",{"2":{"46":4,"571":2,"578":2,"610":2}}],["sign",{"2":{"43":4}}],["signature",{"2":{"43":2}}],["steparg",{"2":{"525":10}}],["step",{"2":{"525":4}}],["steps",{"2":{"203":2,"396":2}}],["studio",{"2":{"440":2}}],["stdout",{"2":{"298":2}}],["strokeopacity",{"2":{"578":12}}],["stroke",{"2":{"577":4,"578":10}}],["strarray",{"2":{"393":2}}],["strarray=",{"2":{"393":2}}],["strawberry",{"2":{"364":6}}],["street",{"2":{"318":6,"319":10}}],["stretch",{"2":{"174":4}}],["str",{"2":{"279":22,"283":18,"302":16,"341":4,"371":6,"372":4,"393":4,"578":10}}],["str4",{"2":{"279":2}}],["str3",{"2":{"279":2}}],["str2",{"2":{"279":2}}],["str1",{"2":{"279":2}}],["strictfunctiontypes",{"2":{"440":2}}],["strictfunctiontypes和",{"2":{"434":1}}],["strict相当于启用",{"2":{"434":1}}],["strictpropertyinitialization",{"0":{"427":1},"2":{"434":1}}],["strict",{"2":{"414":4,"419":2,"427":1,"440":4}}],["strictnullchecks或启用",{"2":{"427":1}}],["strictnullchecks",{"0":{"434":1},"2":{"134":1,"414":2,"434":1,"440":2}}],["strictnullchecks后",{"2":{"134":1}}],["string类型",{"2":{"432":1}}],["string\\t",{"2":{"401":2}}],["stringify",{"2":{"157":2,"527":2,"599":2}}],["string",{"2":{"13":20,"15":6,"95":4,"96":8,"108":6,"113":4,"125":8,"130":2,"144":12,"261":2,"318":2,"335":6,"399":16,"400":18,"402":2,"404":4,"405":8,"406":18,"407":6,"409":4,"410":4,"412":6,"414":6,"424":14,"426":2,"427":2,"431":1,"434":2,"506":2,"510":1,"531":2,"551":2,"610":8}}],["stylus",{"2":{"488":1}}],["stylus等语法转换",{"2":{"149":1}}],["style=",{"2":{"347":8,"551":4,"577":6,"610":2}}],["style3",{"2":{"92":10}}],["style2",{"2":{"92":10}}],["style1",{"2":{"92":10}}],["styleurls",{"2":{"85":4,"103":2,"104":2,"105":2,"106":2,"109":2,"113":2,"114":2,"116":8}}],["stylesheets",{"2":{"457":2}}],["styles",{"2":{"84":2,"89":2,"90":2,"91":2,"92":2,"93":2,"113":2,"602":1}}],["style",{"2":{"15":4,"91":10,"92":6,"116":8,"125":2,"177":2,"458":1,"491":14,"574":4,"577":14,"578":28,"580":2}}],["star1",{"2":{"499":6}}],["star",{"2":{"499":6}}],["startpoint",{"2":{"578":6}}],["start来启动开发服务器",{"2":{"421":1}}],["startdate",{"2":{"294":10}}],["startuptype",{"2":{"234":3}}],["startingdirectory",{"2":{"231":2}}],["start",{"2":{"51":2,"56":2,"72":1,"158":2,"168":4,"172":6,"173":6,"174":4,"234":3,"294":4,"420":2,"499":2,"520":6,"586":2,"587":2,"603":2}}],["startswith",{"2":{"46":2,"302":2,"530":1,"599":2}}],["stack",{"2":{"279":18,"543":10}}],["stash",{"2":{"212":4}}],["standalone",{"2":{"118":4}}],["standalone设为true",{"2":{"118":1}}],["statsync",{"2":{"599":2}}],["state已更新",{"2":{"147":1}}],["state",{"0":{"143":1},"2":{"141":1,"143":4,"156":2}}],["statement3",{"2":{"129":2}}],["statement2",{"2":{"129":2}}],["statement1",{"2":{"129":2}}],["static",{"2":{"42":2,"103":6,"105":4,"106":2,"121":2,"144":2,"269":2,"303":6,"304":6,"312":4,"313":1,"314":2,"315":14,"406":1,"408":4,"479":1}}],["status",{"2":{"30":4,"42":10,"43":10,"72":1,"158":4,"303":6,"304":10,"305":4,"306":4,"307":8,"308":6,"309":4,"310":6,"311":6,"315":16}}],["storeid",{"2":{"506":1}}],["store",{"0":{"156":1},"2":{"156":2,"222":1}}],["storage",{"2":{"46":2}}],["stopimmediatepropagation",{"2":{"528":1}}],["stoppropagation",{"2":{"528":1}}],["stopsignal",{"2":{"61":2}}],["stop",{"2":{"56":2,"72":1,"478":8}}],["stock",{"2":{"22":8}}],["spec",{"2":{"439":2,"440":2}}],["specifies",{"2":{"432":2}}],["specified",{"2":{"420":2}}],["speak",{"2":{"245":6,"246":2,"247":2}}],["spelling",{"2":{"230":2}}],["space",{"2":{"167":8,"176":2,"197":2,"611":2}}],["span",{"2":{"113":4,"137":4,"172":4,"347":20,"610":16}}],["spark",{"2":{"15":8}}],["sparkmd5",{"2":{"15":4}}],["splitpath",{"2":{"599":8}}],["splitchunks",{"2":{"571":2}}],["split",{"2":{"46":2,"283":2,"302":8,"357":4,"371":2,"530":1,"578":4,"599":2}}],["splice",{"2":{"15":2,"289":2,"319":2}}],["suoxiao",{"2":{"577":2}}],["super",{"2":{"271":2,"405":2,"406":6}}],["sure",{"2":{"234":2,"586":2}}],["such",{"2":{"234":1}}],["successfully",{"2":{"235":1}}],["success",{"2":{"30":4,"42":2,"89":4,"90":2,"158":6,"159":6,"239":2,"574":4,"610":2}}],["succ",{"2":{"10":2,"11":2,"12":4}}],["sum2",{"2":{"264":2}}],["sum",{"2":{"84":2,"146":2,"263":2,"378":2,"380":6,"384":4,"408":4,"539":6}}],["sudo",{"2":{"51":2}}],["subject",{"2":{"384":6}}],["substr",{"2":{"530":1,"578":2}}],["substring区别",{"0":{"532":1}}],["substring",{"2":{"15":2,"530":1,"532":12}}],["subscribe",{"2":{"104":2,"113":2}}],["submit",{"2":{"46":2,"111":1,"112":1}}],["score",{"2":{"384":8}}],["scoped",{"2":{"15":2,"488":1}}],["sc=han",{"2":{"345":2}}],["scrollhandler",{"2":{"615":2}}],["scrollheight",{"2":{"577":2,"614":6}}],["scrollleft",{"2":{"615":4}}],["scrolltop",{"2":{"614":2}}],["scrollwidth",{"2":{"577":2}}],["scroll",{"2":{"249":2,"577":2,"614":2}}],["scrollbar",{"2":{"177":12}}],["scripthost等",{"2":{"431":1}}],["scripthost",{"2":{"414":2,"431":2}}],["scripts",{"2":{"75":2,"420":2,"563":1,"564":1,"573":2}}],["script",{"2":{"15":4,"45":4,"139":16,"150":1,"151":8,"152":8,"153":8,"220":2,"230":2,"303":8,"456":1,"610":4,"614":4}}],["scss",{"2":{"15":2,"85":2,"113":2,"488":1,"491":1,"583":1}}],["schema",{"2":{"13":10,"224":4,"227":2}}],["serve",{"2":{"420":2,"563":1,"573":4}}],["serverstatus",{"2":{"36":2}}],["server",{"2":{"20":6,"21":6,"22":12,"30":2,"42":2,"43":2,"46":2,"211":12,"417":2,"418":2,"573":2}}],["service",{"0":{"496":1},"2":{"234":6,"563":6,"573":6}}],["sepia",{"2":{"193":2}}],["self",{"2":{"174":14,"364":4,"495":3,"578":4}}],["selectnode",{"2":{"574":2}}],["selectsort",{"2":{"288":2}}],["selected",{"2":{"123":2}}],["select=",{"2":{"102":6}}],["selector",{"2":{"84":2,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":4,"96":4,"103":2,"104":2,"105":2,"106":2,"108":2,"109":2,"113":4,"114":2,"116":8,"119":2,"121":6,"122":2,"123":2,"125":2,"126":4,"130":4}}],["select",{"2":{"4":4,"13":2,"34":2,"35":2,"357":2,"483":1,"574":2}}],["section",{"2":{"102":6,"126":4,"605":2}}],["secondary",{"2":{"89":4,"491":8}}],["secrets",{"2":{"396":10}}],["secretkey",{"2":{"43":8}}],["secret",{"2":{"42":2,"43":4}}],["searchdone",{"2":{"612":6}}],["searchplugin",{"2":{"602":4}}],["searchnode",{"2":{"300":8}}],["searchconds",{"2":{"157":6,"158":2}}],["search",{"2":{"55":4,"158":2,"300":4,"601":2,"602":2}}],["sessionstorage",{"2":{"472":1,"522":1,"523":9}}],["session配置后才有",{"2":{"42":2}}],["session",{"0":{"42":1},"2":{"42":26}}],["setitem",{"2":{"523":4}}],["setinterval是异步",{"2":{"526":1}}],["setinterval",{"2":{"111":1,"314":4,"477":1}}],["setuint8",{"2":{"332":2}}],["setup",{"2":{"15":2,"45":2,"151":2,"152":2,"153":2,"396":5,"614":2}}],["setmonth",{"2":{"294":2}}],["setname",{"2":{"270":4}}],["setting",{"2":{"433":6}}],["settings",{"2":{"396":4}}],["settimeout",{"2":{"111":1,"146":1,"238":7,"240":2,"293":2,"295":2,"306":4,"307":6,"308":4,"309":4,"310":4,"311":4,"315":8,"493":4,"494":2,"519":4,"520":4,"525":4,"526":2,"577":2,"584":4}}],["setter方法",{"2":{"270":2}}],["setter方法操作属性带来的好处",{"2":{"270":1}}],["setattribute",{"2":{"249":2,"250":2}}],["setsate",{"2":{"147":4}}],["setstate",{"2":{"143":2,"146":4,"578":2}}],["setval",{"2":{"118":2}}],["setoptions",{"2":{"113":4}}],["setheader",{"2":{"20":2,"21":2,"22":4}}],["set",{"0":{"266":1},"2":{"13":2,"36":2,"37":4,"38":2,"211":5,"220":2,"265":2,"266":8,"270":4,"296":4,"316":4,"322":8,"323":2,"324":10,"374":2,"395":2,"407":2,"431":1,"536":4,"584":2,"590":4}}],["send",{"2":{"9":2,"28":2,"29":8,"30":4,"42":10,"43":10,"46":2}}],["sex=",{"2":{"144":6}}],["sex默认值为男",{"2":{"144":2}}],["sex",{"2":{"4":12,"5":4,"144":14}}],["shift",{"2":{"493":2,"512":2,"543":2,"544":4}}],["shine",{"2":{"179":6}}],["shenzhen",{"2":{"318":6,"319":10}}],["shellsort",{"2":{"291":2}}],["shellshow",{"2":{"2":1}}],["shell配置文件",{"2":{"228":1}}],["shell启动时执行的脚本",{"2":{"227":1}}],["shell选择自己安装的字体",{"2":{"225":1}}],["shell",{"2":{"61":2,"224":2,"227":2,"235":1}}],["shellfor",{"2":{"5":1}}],["shelldb",{"2":{"4":12,"5":2,"6":1,"7":1}}],["shelluse",{"2":{"1":1}}],["shouldend",{"2":{"577":2}}],["should",{"2":{"295":2}}],["shortcuts",{"2":{"586":2,"587":2}}],["short",{"2":{"268":2}}],["showdirectorypicker",{"2":{"357":2}}],["showdatacomponent",{"2":{"113":2}}],["showsavefilepicker",{"2":{"334":2}}],["showopenfilepicker",{"2":{"333":2,"334":2}}],["showunless",{"2":{"126":14}}],["showalert",{"2":{"113":2}}],["show",{"2":{"1":2,"113":6,"126":2,"610":2}}],["shape",{"2":{"578":44}}],["shapestyle",{"2":{"578":8}}],["sharedmemory",{"2":{"414":4}}],["sha",{"2":{"210":2}}],["shadow",{"2":{"102":6,"183":2,"185":2,"191":1,"192":2,"195":4,"199":2,"200":4}}],["shadowdom",{"2":{"101":1}}],["sh",{"2":{"61":2,"395":3}}],["shshow",{"2":{"1":1}}],["查找强联通分量",{"2":{"547":1}}],["查找拓扑排序",{"2":{"547":1}}],["查找图的最小生成树",{"2":{"546":1}}],["查找连通块",{"2":{"546":1,"547":1}}],["查找最短路径",{"2":{"546":1}}],["查",{"2":{"530":1}}],["查询某些属性或调用某些方法",{"2":{"465":1}}],["查询结果",{"2":{"35":2}}],["查询语句",{"2":{"35":2}}],["查询数据",{"0":{"35":1},"2":{"577":2}}],["查询名字中含有",{"2":{"4":2}}],["查询条件中使用查询操作符",{"2":{"4":1}}],["查询符合条件的第一个",{"2":{"4":2}}],["查询第一个",{"2":{"4":2}}],["查询所有",{"2":{"4":4}}],["查询",{"0":{"4":1,"12":1},"2":{"4":2}}],["查看私钥列表",{"2":{"234":1}}],["查看生成的公钥",{"2":{"233":1}}],["查看生成的文件",{"2":{"232":1}}],["查看nginx进程",{"2":{"72":1}}],["查看nginx运行状态",{"2":{"72":1}}],["查看nginx版本等信息",{"2":{"72":1}}],["查看网卡",{"2":{"75":2}}],["查看网卡信息",{"2":{"62":2}}],["查看网络源数据",{"2":{"62":2}}],["查看网络",{"2":{"62":2}}],["查看容器内部细节",{"2":{"58":1}}],["查看容器内部细节docker",{"2":{"58":1}}],["查看容器日志",{"0":{"58":1},"2":{"58":2}}],["查看数据库集合\\tshow",{"2":{"2":2}}],["查看所在数据库",{"2":{"1":2}}],["查看所有数据库",{"2":{"1":1}}],["1f12aa",{"2":{"348":2}}],["1fr",{"2":{"165":2}}],["1=1",{"2":{"296":6}}],["1+1",{"2":{"290":1}}],["137",{"2":{"578":2}}],["138",{"2":{"578":4}}],["133",{"2":{"578":6}}],["132",{"2":{"578":2}}],["131",{"2":{"493":2}}],["13121a",{"2":{"178":2}}],["13",{"0":{"438":1},"2":{"285":2,"318":6,"319":8,"331":2,"578":2}}],["17",{"2":{"194":1}}],["17+",{"2":{"147":1}}],["1em",{"2":{"185":2,"195":4,"201":2}}],["1536px",{"2":{"489":2}}],["15em",{"2":{"199":2}}],["155",{"2":{"190":6}}],["15px",{"2":{"183":4,"186":2}}],["1500",{"2":{"578":4}}],["150",{"2":{"179":2,"578":2}}],["15",{"2":{"179":2,"195":2,"297":8,"331":2}}],["168",{"2":{"589":4}}],["169",{"2":{"578":2}}],["1677728421211",{"2":{"533":1}}],["1677728421211number",{"2":{"533":1}}],["1678519417983",{"2":{"316":2}}],["16",{"2":{"116":4,"130":2,"147":1,"370":2,"490":2,"526":1}}],["111",{"2":{"385":8}}],["110deg",{"2":{"481":4}}],["110",{"2":{"362":2,"578":2}}],["11",{"0":{"94":1,"261":1,"436":1},"2":{"319":2,"333":2,"365":2,"418":2,"423":2,"532":8,"533":2,"540":2,"578":2}}],["1px",{"2":{"91":4,"92":6,"168":2,"170":2,"199":2,"200":24,"482":4,"603":2}}],["142",{"2":{"578":2}}],["143",{"2":{"494":2,"578":2}}],["141",{"2":{"494":2}}],["1415926",{"2":{"408":2}}],["14",{"0":{"439":1},"2":{"66":2,"331":2}}],["1agt",{"2":{"55":1}}],["120",{"2":{"584":4}}],["12020",{"2":{"342":2}}],["12px",{"2":{"509":2,"603":2}}],["1280px",{"2":{"489":2}}],["12\\t",{"2":{"255":2}}],["123function",{"2":{"524":1}}],["123+",{"2":{"253":1}}],["123",{"2":{"253":7,"255":2,"373":4,"399":2,"408":2,"434":2,"524":5,"527":2}}],["123456",{"2":{"341":2}}],["12345",{"2":{"150":2}}],["127",{"2":{"20":2,"30":2,"34":2,"42":2,"43":2}}],["12",{"0":{"437":1},"2":{"18":2,"256":2,"302":2,"509":2,"577":2,"578":2}}],["1080",{"2":{"583":2}}],["109",{"2":{"578":2}}],["105",{"2":{"578":2}}],["1058",{"2":{"234":1}}],["102",{"2":{"578":4}}],["10240",{"2":{"613":2}}],["1024px",{"2":{"489":2}}],["1024代表",{"2":{"489":1}}],["1024",{"2":{"15":8,"402":2}}],["10function",{"2":{"536":1}}],["1010",{"2":{"533":2}}],["10let",{"2":{"510":1}}],["10const",{"2":{"380":1}}],["10个",{"2":{"347":2}}],["10a",{"2":{"251":1}}],["10+",{"2":{"177":2}}],["10px",{"2":{"113":4,"168":2,"170":2,"183":2,"184":4,"189":2,"482":2,"491":10,"603":2}}],["10",{"0":{"93":1,"260":1,"278":1,"350":1,"435":1},"1":{"351":1,"352":1,"353":1},"2":{"156":2,"157":4,"159":2,"251":13,"252":6,"256":2,"260":2,"262":2,"268":2,"302":4,"347":4,"348":2,"380":3,"384":2,"389":8,"393":2,"476":1,"495":2,"510":7,"533":6,"536":3,"540":10,"551":2,"577":4,"578":14,"585":4}}],["100vw",{"2":{"583":2}}],["100vh",{"2":{"202":2,"583":2}}],["1000ms",{"2":{"526":1}}],["1000",{"2":{"314":2,"476":1,"493":2,"494":2,"525":4,"578":2}}],["1000100001",{"2":{"302":2}}],["100000",{"2":{"288":2}}],["10000",{"2":{"288":2,"578":2}}],["1000px",{"2":{"201":2}}],["100px",{"2":{"15":4,"165":6,"168":4,"170":4,"190":18,"195":4,"482":4}}],["100",{"0":{"362":1},"2":{"15":2,"178":6,"180":2,"184":4,"186":6,"188":8,"195":2,"199":2,"203":2,"307":2,"362":2,"476":1,"478":12,"490":4,"493":2,"494":2,"536":2,"551":4,"577":2,"578":2,"602":2,"603":2,"614":4,"615":2}}],["192",{"2":{"589":4}}],["1920",{"2":{"583":2}}],["195",{"2":{"578":2}}],["19\\t",{"2":{"401":2}}],["190",{"2":{"362":2,"578":2}}],["199",{"2":{"190":6,"578":2}}],["19",{"2":{"5":4,"35":2,"144":2,"332":2}}],["186px",{"2":{"611":2}}],["186",{"2":{"578":2}}],["1890ff",{"2":{"578":2}}],["18px",{"2":{"577":2}}],["18const",{"2":{"540":1}}],["18deg",{"2":{"481":4}}],["18db",{"2":{"4":1}}],["184",{"2":{"198":2}}],["180deg",{"2":{"195":2}}],["18",{"2":{"4":3,"5":4,"6":2,"7":6,"25":2,"29":4,"30":2,"144":8,"265":4,"318":6,"319":10,"399":2,"400":2,"406":6,"498":6,"502":2,"540":1,"578":2}}],["1",{"0":{"4":1,"9":1,"20":1,"24":1,"28":1,"31":1,"34":1,"40":1,"54":1,"66":1,"70":1,"84":1,"116":1,"227":1,"232":1,"251":1,"340":1,"416":1,"426":1},"2":{"4":14,"12":2,"15":6,"16":2,"20":2,"30":6,"34":8,"35":2,"36":4,"38":2,"42":6,"43":2,"46":2,"55":7,"61":4,"80":1,"84":4,"92":1,"103":2,"107":2,"108":2,"116":4,"125":2,"137":7,"139":2,"140":1,"143":2,"145":4,"146":1,"147":25,"157":8,"158":2,"159":12,"172":14,"178":4,"180":2,"189":4,"190":4,"193":2,"195":8,"198":2,"199":2,"202":2,"203":2,"213":4,"239":10,"243":9,"247":2,"255":10,"260":2,"267":4,"268":4,"270":2,"279":3,"281":8,"283":4,"285":10,"287":4,"288":2,"289":4,"290":8,"291":2,"292":4,"294":2,"295":4,"296":20,"297":2,"298":2,"299":10,"301":10,"302":18,"303":2,"304":2,"315":2,"316":18,"318":6,"319":22,"321":2,"322":6,"324":6,"326":4,"327":2,"329":4,"330":4,"346":10,"349":4,"357":4,"363":4,"364":10,"365":6,"370":4,"372":4,"373":4,"378":1,"380":4,"381":6,"382":4,"383":4,"385":16,"389":12,"393":2,"399":6,"402":4,"420":2,"422":1,"424":2,"432":4,"434":4,"440":2,"448":1,"468":1,"476":1,"482":5,"495":6,"509":1,"512":4,"539":8,"540":4,"542":14,"564":2,"571":2,"577":4,"578":18,"585":14,"588":1,"599":8,"602":1,"614":6}}],["四次挥手",{"0":{"468":1}}],["四位一组",{"2":{"302":2}}],["四分之一椭圆",{"2":{"188":1}}],["四分之一椭圆border",{"2":{"188":1}}],["四",{"0":{"3":1,"23":1,"50":1,"306":1,"409":1,"454":1,"459":1},"1":{"4":1,"5":1,"6":1,"7":1,"24":1,"25":1,"410":1},"2":{"302":6}}],["李四",{"2":{"2":2,"5":4,"35":2,"122":2}}],["crawllinks",{"2":{"590":2}}],["credentials",{"2":{"396":2}}],["createrange",{"2":{"574":2}}],["createref调用后可以返回一个容器",{"2":{"145":2}}],["createref形式",{"2":{"145":4}}],["createref",{"2":{"145":2}}],["created",{"0":{"557":1,"558":1},"2":{"555":2,"556":6,"559":2}}],["createtask",{"2":{"493":4,"494":4}}],["createeventobject",{"2":{"584":2}}],["createevent",{"2":{"584":4}}],["createelement",{"2":{"375":6,"574":2,"577":2}}],["createembeddedview",{"2":{"126":2}}],["createobjecturl",{"2":{"335":4}}],["createwritable",{"2":{"334":4}}],["create",{"2":{"62":2,"113":2,"552":1}}],["createpool",{"2":{"34":2}}],["createserver",{"2":{"20":2,"21":2,"22":4}}],["createfilechunk",{"2":{"15":4}}],["createat",{"2":{"13":2}}],["createcollection",{"2":{"2":2}}],["creeateat",{"2":{"12":2}}],["c`",{"2":{"586":4}}],["c396ed",{"2":{"578":4}}],["cfg",{"2":{"578":62,"580":2}}],["cfr",{"2":{"113":4}}],["c为2",{"2":{"399":2}}],["cicle",{"2":{"578":2}}],["circular",{"2":{"577":2}}],["circle",{"2":{"178":4,"578":12,"610":4}}],["city",{"2":{"318":6,"319":10}}],["cycle",{"2":{"311":2,"315":2}}],["cy=",{"2":{"178":2}}],["cstr",{"2":{"302":12}}],["css下重新覆盖样式",{"2":{"602":1}}],["css3",{"2":{"478":1}}],["css基础面试题",{"0":{"473":1},"1":{"474":1,"475":1,"476":1,"477":1,"478":1,"479":1,"480":1,"481":1,"482":1,"483":1,"484":1,"485":1,"486":1,"487":1,"488":1,"489":1}}],["cssom",{"2":{"455":2,"456":2}}],["cssfooter",{"2":{"201":1}}],["csstext",{"2":{"200":1}}],["cssdd+dt",{"2":{"197":1}}],["csshyphens",{"2":{"197":1}}],["csshtml",{"2":{"177":1}}],["cssimg",{"2":{"193":1}}],["cssbody",{"2":{"202":1}}],["cssborder",{"2":{"188":1}}],["cssbox",{"2":{"183":1,"192":1,"195":1}}],["cssbackground",{"2":{"184":1,"185":1}}],["csssvg",{"2":{"178":1}}],["css常用代码段",{"0":{"175":1},"1":{"176":1,"177":1,"178":1,"179":1,"180":1}}],["css",{"0":{"181":1,"457":1,"476":1,"567":1},"1":{"182":1,"183":1,"184":1,"185":1,"186":1,"187":1,"188":1,"189":1,"190":1,"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"198":1,"199":1,"200":1,"201":1,"202":1,"203":1},"2":{"98":1,"99":2,"103":2,"104":2,"105":2,"106":2,"109":2,"114":2,"116":8,"161":1,"164":1,"166":1,"167":2,"168":1,"170":1,"172":1,"173":2,"174":1,"176":2,"179":1,"180":1,"181":1,"186":1,"189":1,"190":1,"195":1,"198":1,"199":1,"203":1,"444":1,"445":1,"449":1,"455":1,"456":4,"474":5,"477":1,"481":1,"482":1,"483":1,"488":2,"489":1,"490":2,"491":1,"548":1,"586":2,"603":1,"605":1,"611":1}}],["cjs",{"2":{"220":2,"357":4}}],["czrc",{"2":{"221":1}}],["cz",{"0":{"221":1},"2":{"218":2,"221":5}}],["cx=",{"2":{"178":2}}],["ccc",{"2":{"98":2,"183":2,"186":8,"195":2,"482":4}}],["cloud",{"2":{"578":4}}],["cloudcombo",{"2":{"578":4}}],["close=",{"2":{"609":2}}],["closed",{"2":{"113":6}}],["close",{"2":{"113":4,"334":4,"584":2,"609":4,"610":2}}],["cleanwebpackplugin",{"2":{"418":4}}],["clean",{"2":{"417":2,"418":4}}],["cleartimeout",{"2":{"519":6,"577":2}}],["clear",{"2":{"126":2,"265":2,"523":4,"577":2}}],["clamp",{"2":{"176":2}}],["classic模块解析方式",{"2":{"432":2}}],["classic",{"2":{"432":2,"440":2}}],["class库的同学",{"2":{"427":1}}],["class同时需要设置strictfunctiontypes选项为false",{"2":{"426":1}}],["class等库",{"2":{"426":1}}],["class=",{"2":{"89":12,"102":2,"104":6,"105":6,"106":2,"113":4,"123":4,"151":2,"152":2,"153":2,"168":8,"170":8,"357":2,"482":8,"577":6,"586":6,"587":4,"610":10,"614":2}}],["class",{"0":{"411":1},"2":{"84":2,"85":2,"89":14,"90":8,"91":2,"92":2,"93":2,"95":4,"96":4,"103":2,"104":2,"105":2,"106":2,"107":2,"108":4,"109":2,"113":6,"114":2,"116":8,"119":2,"121":6,"122":6,"123":2,"125":2,"126":6,"130":4,"140":2,"143":2,"144":2,"145":1,"269":2,"270":2,"271":4,"293":2,"296":2,"298":2,"299":2,"303":1,"304":1,"315":1,"404":3,"405":4,"406":6,"407":1,"408":1,"409":3,"410":3,"411":4,"426":3,"427":2,"493":2,"502":3,"586":4}}],["clientwidth",{"2":{"615":4}}],["cli3",{"2":{"432":1}}],["cli3的typescript模板",{"2":{"429":1}}],["cli与",{"0":{"220":1}}],["click=",{"2":{"357":2,"610":6}}],["click",{"2":{"86":2,"93":6,"96":2,"108":2,"111":1,"112":1,"113":2,"116":8,"121":2,"126":2,"130":4,"574":6,"577":4,"609":2,"610":2}}],["cli",{"0":{"563":1},"2":{"51":2,"218":1,"220":2,"417":2,"418":2,"563":6,"573":6}}],["cd",{"2":{"75":2,"395":6}}],["cmd和es6",{"2":{"549":1}}],["cmdlet",{"2":{"230":2}}],["cmd等",{"2":{"149":1}}],["cmd等指令运行时的用户身份",{"2":{"61":2}}],["cmd",{"2":{"61":4}}],["cpe",{"2":{"578":4}}],["cp",{"2":{"59":2}}],["ctrl+q+p",{"2":{"56":2}}],["cnssh",{"2":{"235":1}}],["cn\\t",{"2":{"235":2}}],["cn",{"2":{"55":8,"235":3,"268":4}}],["center",{"2":{"92":6,"167":4,"168":12,"170":4,"174":4,"474":12,"551":4,"577":4,"578":14,"580":2,"586":6,"587":6,"603":4}}],["centos7联网",{"0":{"75":1}}],["centos",{"2":{"51":2,"70":1}}],["centos安装docker",{"0":{"51":1}}],["ce",{"2":{"51":8}}],["ceil",{"2":{"15":2,"159":2}}],["cboxss",{"2":{"106":4}}],["cboxs",{"2":{"106":4}}],["cbox",{"2":{"105":14,"106":14}}],["cb",{"2":{"46":8}}],["c",{"2":{"17":2,"61":8,"145":12,"146":2,"168":12,"170":12,"173":4,"231":2,"232":2,"326":2,"371":8,"393":2,"399":4,"426":2,"539":8,"551":4,"578":20,"586":18,"587":16,"603":2}}],["custom",{"2":{"586":2}}],["customtitle",{"2":{"87":4}}],["customrequest",{"2":{"15":4}}],["cur+pre",{"2":{"539":2}}],["curring",{"2":{"539":6}}],["currunit",{"2":{"302":8}}],["currentwidth",{"2":{"578":10}}],["currentvalue",{"2":{"360":4,"368":4,"378":5}}],["current",{"2":{"290":10,"298":22,"300":38,"551":6}}],["current插入到arr",{"2":{"290":1}}],["currentrow",{"2":{"159":2}}],["currentchange",{"2":{"158":2}}],["currentpage",{"2":{"157":4,"158":4,"159":18}}],["currentitem",{"2":{"95":4}}],["curpage",{"2":{"159":6}}],["cursor",{"2":{"113":2,"577":4}}],["cur",{"2":{"15":20,"326":14,"327":6,"381":6,"383":8,"384":4,"385":8,"539":14,"599":14}}],["china",{"2":{"585":4}}],["chinese",{"2":{"384":2}}],["children",{"2":{"357":14,"474":6,"542":6,"543":10,"544":10,"578":8,"579":2}}],["child1",{"2":{"180":2}}],["childs1",{"2":{"104":6}}],["childs",{"2":{"104":4}}],["childdata",{"2":{"103":12}}],["childinstance",{"2":{"103":12}}],["childcomponent",{"2":{"103":10,"104":8}}],["child",{"2":{"98":6,"103":4,"104":16,"105":14,"106":11,"180":2,"197":1,"375":2,"502":4,"503":6,"504":4,"543":12,"544":4}}],["ch",{"2":{"279":17}}],["cherry",{"2":{"216":2}}],["checkbox",{"2":{"611":4}}],["checkjs",{"2":{"414":2,"440":2}}],["check",{"2":{"230":2,"610":2}}],["checkout",{"2":{"212":2,"217":2,"396":5,"607":1}}],["checkfile",{"2":{"15":2}}],["checkfileexist",{"2":{"15":4}}],["chrome",{"2":{"177":2,"194":1,"418":2,"420":2,"423":2,"450":1}}],["chatgpt",{"2":{"588":1}}],["chaining",{"2":{"311":2,"315":2}}],["chart",{"2":{"584":8}}],["chartsinstance",{"2":{"584":4}}],["chartloading",{"2":{"577":4}}],["charcodeat与fromcharcode",{"0":{"531":1}}],["charcodeat",{"2":{"530":1,"531":2}}],["charset",{"2":{"491":2}}],["charset=utf",{"2":{"20":4,"21":2,"22":4}}],["char",{"2":{"302":6}}],["charat",{"2":{"279":2,"530":1}}],["changeorigin",{"2":{"589":2}}],["changelog",{"0":{"221":1},"2":{"218":3,"221":6}}],["changeweather",{"2":{"143":2}}],["change",{"2":{"116":8}}],["changedetection",{"2":{"113":2}}],["changedetectionstrategy",{"2":{"111":2,"112":2,"113":4,"121":2}}],["changedetectorref",{"2":{"112":2}}],["changedrows",{"2":{"36":2}}],["changes",{"2":{"104":6,"109":6,"126":4}}],["change=",{"2":{"45":2}}],["chunkcount",{"2":{"15":4}}],["chunk",{"2":{"15":18}}],["chunksize",{"2":{"15":8}}],["chunks",{"2":{"15":26,"571":6}}],["canceledit",{"2":{"610":6}}],["cancelupdate",{"2":{"610":2}}],["cancelable",{"2":{"584":2}}],["cannot",{"0":{"586":1},"1":{"587":1},"2":{"588":1}}],["canvases",{"2":{"551":2}}],["canvas画图片",{"2":{"551":2}}],["canvas是更好的选择",{"2":{"484":1}}],["canvas是一种基于位图的绘图技术",{"2":{"484":1}}],["canvas要求开发者掌握像素级别的操作",{"2":{"484":1}}],["canvas和svg都是用于创建图形的html5元素",{"2":{"484":1}}],["canvas和svg区别",{"0":{"484":1}}],["canvas",{"2":{"335":2,"551":11,"577":4}}],["canfly",{"2":{"108":24}}],["carr",{"2":{"302":4}}],["cachegroups",{"2":{"571":2}}],["cache",{"2":{"296":50,"450":1,"471":2}}],["cached",{"2":{"208":4}}],["capacity",{"2":{"296":8}}],["campbell",{"2":{"231":2}}],["case",{"2":{"137":2,"259":2,"440":2}}],["calc",{"2":{"184":4,"201":2}}],["calcfilehash",{"2":{"15":4}}],["called",{"2":{"426":2}}],["call和bind与apply",{"2":{"262":1}}],["callbacks",{"2":{"307":4,"308":2,"310":2,"311":2,"315":8}}],["callback",{"2":{"250":4,"307":8,"315":8,"368":2,"378":6}}],["call",{"2":{"130":2,"262":5,"318":4,"504":2,"507":1}}],["callphone",{"2":{"130":6}}],["cat",{"2":{"13":4,"59":2,"233":1,"347":6}}],["catch捕获异常",{"2":{"242":2}}],["catch",{"2":{"9":2,"10":2,"11":2,"12":4,"45":2,"239":4,"242":2,"295":8,"304":2,"306":4,"308":8,"309":4,"310":10,"311":2,"315":4,"493":2,"494":2}}],["could",{"2":{"234":3}}],["count++",{"2":{"295":2,"494":2}}],["countdocuments",{"2":{"12":2}}],["count",{"2":{"4":2,"12":2,"36":6,"122":8,"295":4,"494":4}}],["code=",{"2":{"577":6}}],["coderfxj",{"2":{"235":1}}],["coder8888",{"2":{"43":2}}],["code终端报错",{"2":{"230":1}}],["code终端配置",{"0":{"230":1}}],["code",{"2":{"228":1,"433":2,"577":8}}],["cos",{"2":{"195":2}}],["correct",{"2":{"217":2,"230":2,"234":2}}],["corner",{"2":{"195":4}}],["corejs版本",{"2":{"423":2}}],["corejs",{"2":{"418":2,"423":2}}],["core",{"2":{"84":2,"85":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":4,"96":4,"103":2,"104":2,"105":2,"106":2,"107":2,"108":4,"109":2,"113":4,"114":2,"116":8,"119":2,"121":6,"122":2,"123":2,"125":2,"126":4,"130":4,"357":2,"414":2,"422":5,"440":2}}],["cors",{"0":{"31":1,"32":1},"2":{"30":6,"43":6}}],["cors解决跨域",{"2":{"30":2}}],["copy",{"2":{"61":4,"574":8}}],["combos",{"2":{"577":4,"578":2}}],["combo",{"2":{"577":2,"578":4}}],["comlet",{"2":{"532":1}}],["com|cn|cc|net|org",{"2":{"346":2}}],["com+",{"2":{"341":2}}],["compressionwebpackplugin",{"2":{"613":2}}],["compileonsave",{"2":{"440":2}}],["compileroptions",{"2":{"414":4,"419":2,"439":2,"440":2}}],["compare",{"2":{"388":4}}],["complete",{"2":{"161":1}}],["computed",{"2":{"157":2,"458":1,"554":1}}],["componentupdated",{"2":{"574":2}}],["components",{"2":{"113":2,"414":2,"433":4,"554":1}}],["componentref",{"2":{"113":20}}],["componentfactoryresolver",{"2":{"113":4}}],["component",{"2":{"84":4,"85":8,"89":4,"90":4,"91":4,"92":4,"93":4,"95":8,"96":8,"100":1,"102":2,"103":11,"104":12,"105":10,"106":10,"108":4,"109":8,"113":16,"114":11,"116":32,"119":4,"121":12,"122":4,"123":4,"126":4,"130":9,"140":2,"143":2,"144":2,"145":2,"375":2,"426":1}}],["composecurl",{"2":{"66":1}}],["compose",{"0":{"540":1},"2":{"51":2,"66":5,"540":8}}],["commonregister",{"2":{"577":4,"578":2}}],["common",{"2":{"488":1,"535":1,"571":4}}],["commonjs规范",{"2":{"549":1}}],["commonjs",{"2":{"149":1,"414":2,"430":3,"440":4}}],["commandline",{"2":{"231":4}}],["commitizen",{"2":{"218":1,"221":2}}],["commitlint",{"0":{"220":2},"2":{"218":3,"220":12}}],["commit",{"2":{"55":2,"210":2,"213":2,"216":2,"221":1,"395":2,"584":2}}],["com",{"2":{"51":2,"55":8,"66":2,"211":22,"229":1,"232":2,"234":2,"235":8,"346":12,"347":12,"349":12,"350":4,"395":2,"396":6,"532":7,"572":1,"573":1}}],["cookies",{"2":{"523":2,"584":2}}],["cookie",{"0":{"41":1},"2":{"41":2,"42":2,"472":1,"522":1,"523":7}}],["collapsible",{"2":{"599":4}}],["collapsed",{"2":{"579":2,"599":4}}],["collection",{"2":{"414":2}}],["collectionname",{"2":{"2":2}}],["collections",{"2":{"2":2}}],["color=",{"2":{"478":4}}],["color​​​",{"2":{"466":1}}],["colorscheme",{"2":{"231":2}}],["colorchange",{"2":{"125":4}}],["color",{"2":{"84":2,"91":2,"99":3,"124":4,"125":6,"177":4,"178":2,"190":6,"203":2,"347":8,"399":8,"491":20,"577":2,"603":4}}],["columns",{"2":{"168":2,"170":2}}],["column",{"2":{"36":2,"166":2,"172":8,"173":6,"180":2,"202":2}}],["concurrencyrequest",{"2":{"494":4}}],["concat",{"2":{"282":10,"289":2,"322":6,"324":6,"326":6,"527":4,"530":1,"539":6,"543":2,"599":2}}],["conic",{"2":{"481":2}}],["convertarr",{"2":{"383":6}}],["conventional",{"0":{"220":1,"221":1},"2":{"218":3,"220":4,"221":6}}],["cond",{"2":{"157":14}}],["conds",{"2":{"157":20,"158":4}}],["condition为false时显示",{"2":{"121":2}}],["condition为true时显示",{"2":{"121":2}}],["condition为假时显示",{"2":{"121":2}}],["condition为真时显示",{"2":{"121":2}}],["condition",{"2":{"121":20}}],["conditions",{"2":{"12":2,"158":2}}],["confirm",{"2":{"610":4}}],["confirmupdate",{"2":{"610":4}}],["configurewebpack",{"2":{"571":2}}],["configs",{"2":{"414":2}}],["config",{"0":{"220":1,"423":1,"573":1},"2":{"13":4,"51":2,"213":2,"218":1,"220":10,"224":2,"227":2,"229":1,"418":1,"440":2,"570":2,"573":1,"586":2,"587":2,"599":2,"602":3,"613":2}}],["conf",{"2":{"61":8,"73":2,"590":2}}],["control",{"2":{"471":2}}],["continue跳过当前循环",{"2":{"260":1}}],["continue",{"2":{"214":2,"357":2}}],["contains",{"2":{"610":2}}],["contain",{"2":{"551":2}}],["container",{"0":{"129":1},"2":{"63":2,"106":2,"113":10,"114":12,"129":4,"482":4,"577":2}}],["containerd",{"2":{"51":2}}],["contactsdata",{"2":{"159":2}}],["context在内部ng",{"2":{"114":2}}],["context",{"2":{"99":2,"114":14,"126":10,"571":2}}],["contentbox",{"2":{"105":4}}],["contentboxcomponent",{"2":{"105":4,"106":8}}],["contentchildren没有",{"2":{"106":2}}],["contentchildren",{"0":{"106":1},"2":{"106":6}}],["contentchildcomponent",{"2":{"105":2,"106":2}}],["contentchild",{"0":{"105":1},"2":{"105":8}}],["content",{"2":{"20":4,"21":10,"22":4,"45":2,"102":16,"105":36,"106":40,"113":10,"123":4,"167":10,"170":4,"179":2,"184":2,"189":2,"190":4,"195":4,"197":4,"198":2,"349":2,"474":8,"475":5,"490":4,"603":4}}],["connecting",{"2":{"234":1}}],["connection",{"2":{"13":2,"234":1}}],["connect",{"2":{"13":2}}],["consolas",{"2":{"198":2}}],["console",{"2":{"10":2,"13":6,"15":2,"16":16,"18":4,"20":2,"21":2,"22":14,"25":8,"28":4,"29":28,"30":6,"34":4,"35":4,"36":8,"37":10,"38":8,"42":2,"43":4,"45":6,"46":2,"93":4,"103":22,"104":6,"105":6,"106":4,"109":16,"113":2,"118":2,"121":2,"125":4,"126":4,"130":2,"145":4,"151":2,"152":2,"153":2,"238":10,"240":4,"241":2,"242":4,"243":6,"245":10,"246":2,"247":2,"262":4,"264":2,"265":4,"269":6,"270":2,"271":4,"272":2,"276":2,"285":2,"293":4,"295":4,"296":18,"297":8,"298":4,"299":6,"301":4,"302":2,"303":2,"307":8,"308":12,"313":4,"314":4,"316":2,"318":6,"319":10,"324":4,"330":4,"331":8,"332":6,"333":2,"340":2,"341":10,"342":4,"346":2,"349":2,"362":2,"363":2,"364":6,"370":2,"372":2,"381":2,"383":2,"384":2,"385":2,"389":4,"393":2,"404":2,"406":6,"407":2,"408":4,"409":2,"410":6,"411":4,"426":4,"427":2,"493":2,"494":8,"495":2,"498":2,"502":2,"503":2,"504":2,"512":2,"524":4,"525":2,"532":20,"536":6,"539":2,"570":3}}],["constlet",{"2":{"402":1}}],["constructor",{"2":{"103":10,"104":2,"105":2,"106":2,"108":2,"109":2,"113":4,"114":2,"116":4,"119":2,"121":2,"125":2,"126":2,"130":4,"269":2,"270":2,"271":4,"274":1,"293":2,"296":2,"298":2,"299":2,"303":2,"304":2,"315":2,"319":4,"404":4,"405":6,"406":12,"407":2,"409":2,"410":2,"493":2,"499":4,"527":4}}],["const",{"0":{"402":1,"514":1,"515":1},"1":{"515":1,"516":1},"2":{"10":2,"11":2,"12":14,"13":23,"15":56,"16":1,"17":2,"18":1,"20":3,"21":5,"22":18,"25":4,"28":3,"29":16,"30":12,"34":3,"35":2,"36":4,"37":4,"42":5,"43":17,"45":2,"46":13,"108":2,"113":4,"137":1,"144":2,"145":2,"157":4,"158":2,"159":4,"240":2,"243":12,"245":2,"246":2,"247":4,"249":5,"250":9,"265":9,"268":1,"271":2,"279":2,"288":2,"289":8,"292":14,"293":1,"294":12,"295":2,"296":10,"299":2,"314":1,"316":18,"318":14,"319":6,"322":8,"326":8,"327":6,"328":4,"329":3,"330":8,"331":1,"332":1,"333":9,"334":22,"335":10,"357":13,"362":1,"364":3,"365":2,"371":1,"372":3,"373":1,"374":4,"378":2,"383":2,"393":5,"402":7,"406":6,"407":2,"409":2,"410":2,"418":6,"493":12,"494":14,"507":1,"514":1,"515":1,"516":2,"536":11,"539":11,"540":12,"544":4,"551":7,"570":2,"571":2,"572":2,"574":6,"577":10,"578":60,"589":2,"599":16,"614":4}}],["ture",{"2":{"500":1}}],["turefunction",{"2":{"500":1}}],["tuple\\t",{"2":{"400":2}}],["tcp",{"2":{"451":3,"452":1}}],["twinkle",{"2":{"203":6}}],["tplvarcomponent",{"2":{"130":2}}],["tpl",{"2":{"130":2}}],["tmppoint",{"2":{"578":6}}],["tmpoutletcomponent",{"2":{"114":2}}],["tmp",{"2":{"114":16}}],["times",{"2":{"493":4,"494":8}}],["timer",{"2":{"238":2,"519":24,"520":8,"577":10}}],["tiff",{"2":{"385":4}}],["tick",{"2":{"112":1}}],["tip",{"2":{"112":1,"118":1,"140":1,"147":1,"249":1,"262":1,"270":1,"274":1,"359":1,"367":1,"378":1,"388":1,"575":1,"594":1,"605":1,"616":1}}],["title=",{"2":{"577":6,"609":2,"610":2}}],["titlecasepipe",{"2":{"132":1}}],["title",{"2":{"11":2,"13":2,"84":6,"87":4,"99":3,"137":2,"303":4,"333":2,"418":2,"542":10,"574":4,"609":2}}],["th",{"2":{"577":4}}],["thu",{"2":{"533":2}}],["thumb",{"2":{"177":2}}],["throttle",{"2":{"520":6}}],["throwfn",{"2":{"551":6}}],["throw",{"2":{"288":2,"302":2,"311":2,"315":2,"519":2,"551":2}}],["that",{"2":{"230":2}}],["thisarg可选",{"2":{"368":2}}],["thisvalue",{"2":{"360":2,"368":2}}],["this表示当前所创建的对象",{"2":{"269":2}}],["this由bind第一个参数决定",{"2":{"262":1}}],["this是新建的对象",{"2":{"262":1}}],["this是调用方法的对象",{"2":{"262":1}}],["this是window",{"2":{"262":1}}],["this的值也不同",{"2":{"262":1}}],["this指向",{"0":{"262":1,"517":1}}],["this",{"2":{"96":4,"103":22,"104":6,"105":6,"106":4,"108":14,"113":34,"116":16,"118":4,"121":6,"125":10,"126":32,"139":2,"140":2,"143":6,"144":2,"145":12,"146":6,"151":4,"152":4,"153":4,"157":20,"158":6,"159":22,"240":2,"241":2,"262":8,"269":10,"270":16,"271":4,"278":2,"293":12,"296":10,"298":4,"299":6,"300":44,"303":20,"304":24,"305":8,"306":8,"307":16,"308":12,"309":8,"310":28,"311":24,"315":54,"404":8,"405":8,"406":24,"407":6,"409":6,"410":6,"427":2,"440":2,"493":28,"495":3,"498":5,"504":2,"519":6,"520":6,"577":56,"578":4,"584":14,"610":22,"612":4,"615":38}}],["the",{"2":{"230":7,"234":4,"347":16,"578":2,"586":2}}],["themes",{"2":{"222":1,"224":2,"227":2}}],["theme",{"2":{"89":4,"113":8,"488":1,"602":1}}],["then方法",{"2":{"315":2}}],["then方法构建",{"0":{"305":1}}],["then的穿透处理",{"2":{"308":4}}],["then的链式操作",{"0":{"308":1}}],["then返回的时promise",{"2":{"308":1}}],["thenblock",{"2":{"121":4}}],["then",{"2":{"15":2,"45":2,"121":2,"239":12,"295":8,"305":2,"307":2,"308":5,"309":4,"310":7,"311":5,"312":2,"313":4,"314":4,"315":10,"357":2,"494":2,"525":4}}],["t\\t",{"2":{"73":2,"122":2}}],["t",{"2":{"36":2,"56":2,"122":2,"126":8,"232":2,"235":6,"424":6}}],["txt",{"2":{"16":14,"18":2,"329":2,"330":2}}],["ts文件",{"2":{"599":2}}],["tslib",{"2":{"440":2}}],["tslint",{"2":{"134":1}}],["tsx",{"2":{"432":4,"439":1}}],["ts中import",{"2":{"432":2}}],["ts中属性具有三种修饰符",{"2":{"406":1}}],["ts模板默认设置为node策略",{"2":{"432":1}}],["ts是有默认推导的",{"2":{"428":1}}],["tsexport",{"2":{"427":1}}],["tsfunction",{"2":{"426":1}}],["ts无法直接转换",{"2":{"422":1}}],["ts$",{"2":{"418":2,"423":2}}],["ts编译器不会报错",{"2":{"431":1}}],["ts编译器可以更具它的信息来对代码进行编译",{"2":{"414":2}}],["ts编译配置",{"0":{"414":1}}],["ts新增类型",{"0":{"400":1}}],["tstype",{"2":{"335":1}}],["tsconfig",{"0":{"425":1,"440":1},"1":{"426":1,"427":1,"428":1,"429":1,"430":1,"431":1,"432":1,"433":1,"434":1,"435":1,"436":1,"437":1,"438":1,"439":1,"440":1},"2":{"134":1,"414":4,"425":1}}],["ts",{"0":{"599":1},"2":{"15":2,"103":1,"104":1,"105":1,"106":1,"113":1,"114":1,"116":2,"151":2,"152":2,"153":2,"334":1,"417":2,"418":8,"423":2,"424":1,"428":1,"432":12,"433":3,"434":1,"439":5,"440":10,"586":2,"587":3,"599":8,"602":3,"614":2}}],["tel",{"2":{"340":4,"342":8}}],["television",{"2":{"95":2}}],["tem",{"2":{"288":4}}],["temp",{"2":{"287":4,"291":6}}],["template中的元素是不可见的",{"2":{"128":1}}],["templateref",{"2":{"121":6,"126":12,"130":1}}],["templateref拓展",{"2":{"121":1}}],["template也可以绑定",{"2":{"114":2}}],["template使用效果一样",{"2":{"114":2}}],["templateurl",{"2":{"85":2,"103":2,"104":2,"105":2,"106":2,"109":2,"113":2,"114":2,"116":2}}],["template",{"0":{"128":1},"2":{"15":8,"45":4,"84":2,"89":2,"90":2,"91":2,"92":2,"93":2,"95":4,"96":4,"108":2,"113":2,"114":24,"116":6,"119":2,"121":28,"122":6,"123":18,"126":2,"128":4,"130":4,"150":4,"151":4,"152":4,"153":4,"165":7,"168":6,"170":6,"418":2,"610":4,"614":4}}],["terminate",{"2":{"495":2}}],["terminal",{"2":{"231":2}}],["term",{"2":{"72":2,"230":2}}],["testmodule",{"2":{"433":2}}],["test指定的时规则生效的文件",{"2":{"418":2}}],["testarr",{"2":{"288":4}}],["test3",{"2":{"144":4}}],["test2",{"2":{"144":2}}],["test1",{"2":{"144":2}}],["test",{"2":{"61":2,"137":1,"143":2,"145":2,"269":2,"302":2,"329":2,"330":2,"340":2,"341":8,"342":4,"346":2,"348":4,"418":2,"420":4,"423":2,"434":2,"500":4,"525":2,"571":2,"578":4,"586":6,"587":4}}],["testdb01",{"2":{"1":4}}],["textval",{"2":{"610":6}}],["textbaseline",{"2":{"578":8,"580":2}}],["textalign",{"2":{"578":14,"580":2}}],["textarea",{"2":{"334":8,"483":1,"574":18}}],["text",{"2":{"20":4,"21":2,"22":4,"92":6,"108":2,"117":6,"139":8,"145":8,"146":4,"176":8,"199":2,"200":2,"301":16,"329":2,"330":2,"334":2,"335":2,"432":1,"474":1,"578":42,"580":4,"599":12,"610":14,"611":2}}],["typeroots",{"2":{"440":2}}],["typeroots和types",{"0":{"438":1}}],["typedarrays",{"2":{"414":2}}],["typeof是按照二进制值进行检测类型的详细转换机制",{"2":{"507":1}}],["typeof",{"2":{"305":4,"308":4,"310":4,"311":4,"315":4,"318":10,"319":2,"400":2,"507":6,"519":6,"527":2}}],["typeerrorlet",{"2":{"311":1}}],["typeerror",{"0":{"586":1},"1":{"587":1},"2":{"295":2,"311":3,"315":2,"509":1,"519":2,"588":1,"592":1}}],["type=",{"2":{"15":2,"45":2,"46":4,"89":12,"90":12,"108":2,"117":2,"123":8,"139":8,"145":8,"146":4}}],["type",{"2":{"13":26,"15":2,"20":4,"21":2,"22":4,"45":2,"113":2,"117":4,"159":4,"220":2,"329":2,"330":2,"335":7,"424":12,"577":8,"610":2}}],["types包",{"2":{"438":1}}],["typescript插件",{"2":{"440":2}}],["typescript1",{"2":{"440":2}}],["typescript是es6的超集",{"2":{"429":1}}],["typescript和es6中引入了class的概念",{"2":{"426":1}}],["typescript带来的类型系统以及强大的ide支持",{"2":{"425":1}}],["typescriptabstract",{"2":{"411":1}}],["typescriptclass",{"2":{"404":1,"405":2,"406":3,"407":1,"408":1,"409":1,"410":1}}],["typescriptchangedetection",{"2":{"111":1,"112":1}}],["typescript字面量\\t",{"2":{"400":1}}],["typescriptenum",{"2":{"399":1}}],["typescriptlet",{"2":{"399":2,"400":3,"401":1,"402":2}}],["typescript",{"0":{"425":1},"1":{"426":1,"427":1,"428":1,"429":1,"430":1,"431":1,"432":1,"433":1,"434":1,"435":1,"436":1,"437":1,"438":1,"439":1,"440":1},"2":{"117":1,"118":1,"123":1,"135":1,"399":4,"400":2,"404":1,"412":1,"417":2,"418":2,"420":1,"440":4,"602":1}}],["typescriptimport",{"2":{"84":1,"85":1,"89":1,"90":1,"91":1,"92":1,"93":1,"95":2,"96":2,"103":1,"104":1,"105":1,"106":1,"107":1,"108":2,"109":1,"113":2,"114":1,"116":4,"119":1,"121":3,"122":1,"123":1,"125":1,"126":2,"130":2}}],["types",{"2":{"10":2,"13":2,"432":2,"438":2,"440":2}}],["tofixed",{"2":{"614":2}}],["toolbar",{"2":{"577":12}}],["tools",{"2":{"408":6}}],["toblob",{"2":{"551":2}}],["tolowercase",{"2":{"530":1}}],["tolocalelowercase",{"2":{"530":1}}],["tolocalestring",{"2":{"268":2}}],["tolocaletimestring",{"2":{"268":2}}],["tolocaledatestring",{"2":{"268":2}}],["touppercase",{"2":{"371":2,"530":1}}],["todataurl",{"2":{"335":2,"551":4}}],["today",{"2":{"95":2}}],["tom",{"2":{"144":2,"318":6,"319":10}}],["tomcat82",{"2":{"64":4}}],["tomcat81",{"2":{"64":4}}],["tomcat",{"2":{"64":8}}],["toggleleftmenu",{"2":{"584":4}}],["toggle",{"2":{"121":2,"126":2}}],["topdirarr",{"2":{"599":4}}],["topochart",{"2":{"577":6}}],["toprimitive",{"2":{"509":1,"512":5,"539":2}}],["top++",{"2":{"279":2}}],["top",{"2":{"113":6,"178":2,"179":2,"189":2,"190":4,"195":4,"249":2,"279":15,"474":4,"479":2,"490":4,"551":2}}],["to",{"2":{"96":2,"161":1,"179":4,"186":2,"195":2,"234":3,"396":8,"478":1,"551":2,"578":2}}],["tostring",{"0":{"533":1},"2":{"46":2,"294":2,"302":4,"316":2,"318":8,"509":1,"512":7,"533":7}}],["tokenstr",{"2":{"43":4}}],["token",{"2":{"43":14,"396":4}}],["total",{"2":{"15":4,"156":2,"158":4,"159":10}}],["totalcount",{"2":{"12":4}}],["tojson",{"2":{"9":2}}],["tailwindcss动态绑定类不能随着渐变",{"0":{"614":1}}],["tailwindcss断点对应设备",{"0":{"489":1}}],["tainted",{"2":{"551":2}}],["table",{"2":{"482":1}}],["tables",{"2":{"2":2}}],["tan",{"2":{"185":2}}],["tar",{"2":{"59":2}}],["tar\\t",{"2":{"59":2}}],["target选项不同而不同",{"2":{"430":1,"431":1}}],["targets",{"2":{"418":2,"423":2}}],["target得到发生事件的dom元素对象",{"2":{"146":1}}],["target",{"0":{"429":1},"2":{"15":2,"45":2,"93":2,"117":2,"146":4,"247":6,"250":2,"326":4,"331":10,"333":2,"335":2,"414":4,"419":2,"426":2,"429":1,"440":2,"589":4,"610":2}}],["tasks",{"2":{"494":20}}],["taskqueue",{"2":{"493":4}}],["task",{"2":{"15":8,"493":12}}],["taskpool",{"2":{"15":18}}],["tagboxwidth",{"2":{"615":2}}],["tagboxref",{"2":{"615":6}}],["taggit",{"2":{"207":1}}],["tag名",{"2":{"207":4}}],["tag",{"2":{"12":6,"55":4,"207":9}}],["taglistwidth",{"2":{"615":4}}],["taglistresizeobserver",{"2":{"615":6}}],["taglistref",{"2":{"615":16}}],["taglist",{"2":{"11":2,"12":2,"13":2}}],["tree",{"2":{"542":2}}],["treenode",{"2":{"299":16}}],["transition",{"2":{"603":2}}],["transpilemodule",{"2":{"440":2}}],["transparent",{"2":{"189":2,"190":4,"195":8,"198":2,"603":4}}],["translatey",{"2":{"195":4,"605":1}}],["translate",{"2":{"178":2,"474":2}}],["transform",{"2":{"107":2,"108":2,"179":2,"189":2,"195":8,"302":4,"464":1,"466":4,"474":3,"479":1,"570":3,"605":2}}],["track",{"2":{"177":2}}],["trackbyhero",{"2":{"122":2}}],["trackbyperson",{"2":{"122":4}}],["trimend",{"2":{"530":1}}],["trimstart",{"2":{"530":1}}],["trim",{"2":{"108":2,"530":1,"610":2}}],["triggered",{"2":{"293":4}}],["trigger",{"2":{"15":2}}],["try",{"2":{"9":2,"10":2,"11":2,"12":4,"230":2,"242":4,"304":2,"306":4,"308":8,"309":4,"310":10,"311":2,"315":4,"493":2,"494":2}}],["truelet",{"2":{"279":1,"340":1,"348":1}}],["true显示",{"2":{"121":2}}],["true",{"2":{"7":4,"11":2,"13":14,"36":2,"42":4,"46":2,"89":4,"90":4,"103":6,"105":4,"106":5,"108":4,"118":4,"121":8,"122":8,"126":2,"134":1,"151":2,"156":2,"158":6,"159":2,"213":2,"214":2,"251":2,"255":2,"256":6,"257":4,"262":4,"279":6,"300":4,"316":2,"318":6,"326":2,"340":1,"341":4,"346":2,"348":1,"359":2,"365":4,"374":2,"400":2,"414":18,"419":2,"440":46,"509":1,"511":1,"512":4,"519":2,"520":4,"528":1,"577":6,"578":14,"579":2,"584":6,"585":4,"589":2,"590":2,"599":4,"610":4,"613":2}}],["三次握手的目的",{"2":{"451":1}}],["三",{"0":{"2":1,"19":1,"49":1,"97":1,"305":1,"324":1,"328":1,"402":1,"407":1,"452":1,"458":1,"581":1},"1":{"20":1,"21":1,"22":1,"98":1,"99":1,"100":1,"101":1,"408":1,"453":1},"2":{"302":6}}],["创建一个新对象",{"2":{"498":1}}],["创建一个普通的js对象",{"2":{"278":1}}],["创建有效的离线体验",{"2":{"497":1}}],["创建package",{"2":{"416":1,"418":2}}],["创建了一个高阶函数",{"2":{"392":1}}],["创建config件",{"0":{"235":1}}],["创建组件",{"2":{"143":2,"144":2}}],["创建组件的示例",{"2":{"113":2}}],["创建类式组件",{"2":{"140":2}}],["创建函数式组件",{"2":{"139":2}}],["创建指定类型的组件工厂",{"2":{"113":2}}],["创建它并插入",{"2":{"78":1}}],["创建服务器",{"0":{"28":1}}],["创建文件",{"2":{"334":2}}],["创建文件hash值",{"2":{"15":2}}],["创建文件唯一",{"2":{"14":1}}],["创建分片",{"2":{"15":2}}],["创建任务池",{"2":{"14":1}}],["创建",{"0":{"20":1},"2":{"1":1,"20":1,"266":2,"615":2}}],["\\tprops",{"2":{"610":2}}],["\\tparent",{"2":{"504":2}}],["\\tgeo",{"2":{"585":2}}],["\\tgetsnapshotbeforeupdate",{"2":{"147":2}}],["\\tgetderivedstatefromprops",{"2":{"147":4}}],["\\tbtns",{"2":{"536":2}}],["\\tthis",{"2":{"503":4,"504":4}}],["\\ttrue",{"2":{"126":2}}],["\\tmounted",{"2":{"610":2}}],["\\tmonths",{"2":{"294":2}}],["\\tmerge",{"2":{"211":4}}],["\\tmethods",{"2":{"157":2,"610":2}}],["\\tarr",{"2":{"289":2}}],["\\tage",{"2":{"144":8}}],["\\tlet",{"2":{"279":2,"525":2}}],["\\tobject",{"2":{"261":2}}],["\\tnew",{"2":{"613":2}}],["\\tnewfn",{"2":{"262":2}}],["\\tnumber",{"2":{"261":2}}],["\\tnan",{"2":{"255":2}}],["\\tname",{"2":{"144":4,"262":2,"610":2}}],["\\t两端为字符串则逐个比较字符的unicode编码\\t",{"2":{"256":2}}],["\\tf",{"2":{"400":2}}],["\\tfalse",{"2":{"255":2}}],["\\tfetch",{"2":{"211":6}}],["\\tundefined",{"2":{"255":2}}],["\\turl",{"2":{"211":8}}],["\\t第一个值为",{"2":{"255":2}}],["\\t++",{"2":{"254":2}}],["\\tif",{"2":{"159":2,"279":2,"365":4,"519":4}}],["\\tdfs",{"2":{"543":2}}],["\\tdata",{"2":{"157":2,"610":2}}],["\\tdb",{"2":{"5":2}}],["\\t2",{"2":{"147":4}}],["\\t12",{"2":{"255":2}}],["\\t1",{"2":{"147":4}}],["\\tremote",{"2":{"211":4}}],["\\treturn",{"2":{"144":2,"146":4,"158":2,"283":2}}],["\\trender",{"2":{"140":2,"143":2,"144":2,"145":2,"147":8}}],["\\tseries",{"2":{"585":2}}],["\\tsex",{"2":{"144":8}}],["\\tshouldcomponentupdate",{"2":{"147":4}}],["\\tshowdata",{"2":{"145":2}}],["\\tspeak",{"2":{"144":2}}],["\\tstate",{"2":{"143":2}}],["\\tcreated",{"2":{"610":2}}],["\\tcomputed",{"2":{"610":2}}],["\\tcomponents",{"2":{"610":2}}],["\\tcomponentdidupdate",{"2":{"147":4}}],["\\tcomponentdidmount",{"2":{"147":4}}],["\\tcomponentwillunmount",{"2":{"147":4}}],["\\tcomponentwillupdate",{"2":{"147":2}}],["\\tcomponentwillmount",{"2":{"147":2}}],["\\tconstructor",{"2":{"147":4,"502":4}}],["\\tconst",{"2":{"144":2}}],["\\tconsole",{"2":{"20":2,"262":2}}],["\\tchangeweather",{"2":{"143":2}}],["\\twatch",{"2":{"610":2}}],["\\twriteconcern",{"2":{"7":2}}],["\\twhere",{"2":{"4":10}}],["\\t\\tminratio",{"2":{"613":2}}],["\\t\\tmaxwidth",{"2":{"610":2}}],["\\t\\tmap",{"2":{"585":2}}],["\\t\\tdeleteoriginalassets",{"2":{"613":2}}],["\\t\\tdocument",{"2":{"610":2}}],["\\t\\texclude",{"2":{"613":2}}],["\\t\\tname",{"2":{"610":2}}],["\\t\\tnull",{"2":{"255":2}}],["\\t\\tthreshold",{"2":{"613":2}}],["\\t\\tthis",{"2":{"143":2,"146":2,"502":4,"612":4}}],["\\t\\ttest",{"2":{"613":2}}],["\\t\\ttextval",{"2":{"610":2}}],["\\t\\tzoom",{"2":{"585":2}}],["\\t\\troam",{"2":{"585":2}}],["\\t\\tregions",{"2":{"585":2}}],["\\t\\trender",{"2":{"375":2}}],["\\t\\trelateoptions",{"2":{"158":2}}],["\\t\\treturn",{"2":{"140":2,"143":2,"144":2,"145":2,"146":2,"157":2,"610":2}}],["\\t\\treactdom",{"2":{"139":2}}],["\\t\\titemstyle",{"2":{"585":2}}],["\\t\\tif",{"2":{"525":2}}],["\\t\\tinitsearchfromcond",{"2":{"157":2}}],["\\t\\t0",{"2":{"255":2}}],["\\t\\talgorithm",{"2":{"613":2}}],["\\t\\taspectscale",{"2":{"585":2}}],["\\t\\tasync",{"2":{"158":2}}],["\\t\\tawait",{"2":{"243":2}}],["\\t\\thandlecurrentchange",{"2":{"158":2}}],["\\t\\thandlesizechange",{"2":{"158":2}}],["\\t\\tcurrentchange",{"2":{"157":2}}],["\\t\\tconst",{"2":{"143":4,"144":2,"145":2}}],["\\t\\tconsole",{"2":{"140":2,"262":2}}],["\\t\\tsuccessupdate",{"2":{"610":2}}],["\\t\\tsuper",{"2":{"502":2}}],["\\t\\tswitchtoedit",{"2":{"610":2}}],["\\t\\tstring",{"2":{"530":1}}],["\\t\\tsizechange",{"2":{"157":2}}],["\\t\\tsearchconddone",{"2":{"158":2}}],["\\t\\tsearch",{"2":{"157":2}}],["\\t\\tfunction",{"2":{"139":2}}],["\\t\\t\\tdefault",{"2":{"610":6}}],["\\t\\t\\tmap",{"2":{"585":2}}],["\\t\\t\\tzoom",{"2":{"585":2}}],["\\t\\t\\tloading",{"2":{"610":2}}],["\\t\\t\\tlabel",{"2":{"585":2}}],["\\t\\t\\tlet",{"2":{"157":4,"158":2,"610":2}}],["\\t\\t\\tgeoindex",{"2":{"585":2}}],["\\t\\t\\tgridloading",{"2":{"157":2}}],["\\t\\t\\tnormal",{"2":{"585":2}}],["\\t\\t\\tqobj",{"2":{"158":6}}],["\\t\\t\\tconds",{"2":{"157":2}}],["\\t\\t\\tconst",{"2":{"157":6,"158":2}}],["\\t\\t\\tconsole",{"2":{"139":2}}],["\\t\\t\\ttext",{"2":{"610":2}}],["\\t\\t\\ttype",{"2":{"585":2,"610":6}}],["\\t\\t\\tthis",{"2":{"157":12,"158":12,"610":16}}],["\\t\\t\\ttrackby",{"2":{"122":2}}],["\\t\\t\\tpaginationoptions",{"2":{"157":2}}],["\\t\\t\\tsearchconds",{"2":{"157":2}}],["\\t\\t\\tinputval",{"2":{"610":2}}],["\\t\\t\\tindex",{"2":{"122":2}}],["\\t\\t\\tisediting",{"2":{"610":2}}],["\\t\\t\\tisechocond",{"2":{"157":2}}],["\\t\\t\\titemstyle",{"2":{"585":2}}],["\\t\\t\\tif",{"2":{"157":2,"158":2,"610":4}}],["\\t\\t\\twrapperloading",{"2":{"157":2}}],["\\t\\t\\t执行了reactdom",{"2":{"139":2}}],["\\t\\t\\treturn",{"2":{"139":2,"146":2,"375":2}}],["\\t\\t\\t\\treturn",{"2":{"610":4}}],["\\t\\t\\t\\tref=",{"2":{"610":2}}],["\\t\\t\\t\\tthis",{"2":{"610":10}}],["\\t\\t\\t\\ttitle=",{"2":{"610":4}}],["\\t\\t\\t\\ttotal",{"2":{"157":2}}],["\\t\\t\\t\\tsize=",{"2":{"610":2}}],["\\t\\t\\t\\tshadowoffsety",{"2":{"585":2}}],["\\t\\t\\t\\tshadowoffsetx",{"2":{"585":2}}],["\\t\\t\\t\\tshadowcolor",{"2":{"585":2}}],["\\t\\t\\t\\tv",{"2":{"610":4}}],["\\t\\t\\t\\tclearable",{"2":{"610":2}}],["\\t\\t\\t\\tclass=",{"2":{"610":4}}],["\\t\\t\\t\\tcurrentpage",{"2":{"157":2}}],["\\t\\t\\t\\temphasis",{"2":{"585":4}}],["\\t\\t\\t\\tnormal",{"2":{"585":4}}],["\\t\\t\\t\\tname",{"2":{"585":2}}],["\\t\\t\\t\\titemstyle",{"2":{"585":2}}],["\\t\\t\\t\\tgroup",{"2":{"157":2}}],["\\t\\t\\t\\toptions",{"2":{"157":2}}],["\\t\\t\\t\\tquery",{"2":{"157":6}}],["\\t\\t\\t\\tpagesize",{"2":{"157":2}}],["\\t\\t\\t\\t\\tborderwidth",{"2":{"585":2}}],["\\t\\t\\t\\t\\tbordertype",{"2":{"585":2}}],["\\t\\t\\t\\t\\tbordercolor",{"2":{"585":2}}],["\\t\\t\\t\\t\\ttextstyle",{"2":{"585":4}}],["\\t\\t\\t\\t\\tthis",{"2":{"158":4}}],["\\t\\t\\t\\t\\tshow",{"2":{"585":2}}],["\\t\\t\\t\\t\\tnormal",{"2":{"585":2}}],["\\t\\t\\t\\t\\tareacolor",{"2":{"585":4}}],["\\t\\t\\t\\t\\tmodel",{"2":{"158":2}}],["\\t\\t\\t\\t\\tlist",{"2":{"158":2}}],["\\t\\t\\t\\t\\tinputwidth",{"2":{"158":2}}],["\\t\\t\\t\\t\\tif",{"2":{"157":2}}],["\\t\\t\\t\\t\\t",{"2":{"157":2,"158":2,"585":6}}],["\\t\\t\\t\\t\\t\\tcolor",{"2":{"585":4}}],["\\t\\t\\t\\t\\t\\tconst",{"2":{"157":2}}],["\\t\\t\\t\\t\\t\\tlabel",{"2":{"585":2}}],["\\t\\t\\t\\t\\t\\topacity",{"2":{"585":2}}],["\\t\\t\\t\\t\\t\\tobj",{"2":{"157":6}}],["\\t\\t\\t\\t\\t\\t\\tcolor",{"2":{"585":2}}],["\\t\\t\\t\\t\\t\\t\\tshow",{"2":{"585":2}}],["\\t\\t\\t\\t\\t\\t\\t",{"2":{"158":2,"263":2}}],["\\t\\t\\t\\t\\t\\t\\t\\t\\tlabel",{"2":{"158":6}}],["\\t\\t\\t\\t\\t\\t\\t\\t\\tname",{"2":{"158":6}}],["\\t\\t\\t\\t\\t\\t\\t\\t",{"2":{"158":12}}],["\\t\\t\\t\\t\\t\\t\\tvaluelist",{"2":{"158":2}}],["\\t\\t\\t\\t\\t\\t\\tplaceholder",{"2":{"158":6}}],["\\t\\t\\t\\t\\t\\t\\tlabel",{"2":{"158":8}}],["\\t\\t\\t\\t\\t\\t\\top",{"2":{"158":8}}],["\\t\\t\\t\\t\\t\\t\\tname",{"2":{"158":8}}],["\\t\\t\\t\\t\\t\\t",{"2":{"158":16,"585":2}}],["\\t\\t\\t\\t\\t\\tthis",{"2":{"157":2}}],["\\t\\t\\t\\t\\t2",{"2":{"139":2}}],["\\t\\t\\t\\t\\t1",{"2":{"139":2}}],["\\t\\t\\t\\t",{"2":{"137":2,"144":6,"145":2,"157":6,"158":4,"209":2,"585":10,"610":12}}],["\\t\\t\\t",{"2":{"137":4,"144":4,"145":6,"157":8,"158":2,"375":4,"585":10,"610":26}}],["\\t\\t",{"2":{"4":2,"137":2,"139":10,"140":4,"144":2,"145":2,"146":2,"157":24,"158":14,"243":2,"255":4,"375":2,"402":2,"520":2,"533":6,"585":8,"610":30}}],["\\t",{"2":{"1":8,"2":8,"4":18,"6":10,"7":8,"16":4,"20":4,"121":2,"122":2,"125":4,"126":4,"130":4,"139":21,"140":2,"143":8,"144":6,"145":8,"146":4,"151":2,"152":2,"153":2,"157":6,"158":2,"206":2,"239":4,"252":4,"255":10,"256":8,"257":6,"259":6,"260":6,"268":2,"269":2,"270":2,"271":2,"276":2,"279":8,"282":4,"289":2,"315":2,"375":2,"399":4,"400":2,"402":6,"412":4,"423":2,"502":4,"523":2,"525":2,"533":2,"536":2,"585":4,"610":14,"612":2,"613":2}}],["dnpm",{"2":{"601":1}}],["dns",{"2":{"450":6}}],["ddd",{"2":{"585":2}}],["dd+dt",{"2":{"197":1}}],["duration",{"2":{"578":18}}],["d+",{"2":{"350":2}}],["djfkdjakdjfkjd",{"2":{"345":2}}],["drag",{"2":{"577":4}}],["drawshape",{"2":{"578":10}}],["drawchart",{"2":{"577":4}}],["drawimage",{"2":{"551":2}}],["draw",{"2":{"466":2,"578":4}}],["drivers",{"2":{"450":1}}],["driective",{"2":{"126":4}}],["drop",{"2":{"2":2}}],["dropdatabase",{"2":{"1":2}}],["dfs",{"0":{"543":1},"2":{"543":11}}],["df",{"2":{"54":2}}],["darwin",{"2":{"592":1}}],["dark",{"2":{"578":2}}],["dance",{"2":{"318":2,"319":6}}],["danger",{"2":{"89":12,"113":2,"134":1,"592":1}}],["dangling=true",{"2":{"55":1}}],["dash",{"2":{"578":2}}],["dashed",{"2":{"168":2,"170":2,"585":2}}],["dasfsada",{"2":{"119":2}}],["day",{"2":{"46":4,"268":2}}],["dataview",{"0":{"332":1},"2":{"332":18}}],["datatype",{"2":{"146":8}}],["database",{"2":{"34":2}}],["databases",{"2":{"1":2}}],["data",{"2":{"15":4,"16":12,"22":8,"30":4,"43":4,"45":2,"46":2,"87":2,"113":6,"158":1,"249":7,"250":6,"335":8,"495":8,"520":2,"523":2,"536":6,"554":1,"577":8,"579":2,"589":6}}],["date类型返回",{"2":{"533":1}}],["date类型转换成unix时间戳",{"2":{"316":1}}],["datestr",{"2":{"346":2}}],["datepipe",{"2":{"132":1}}],["date",{"2":{"13":8,"46":12,"108":2,"268":2,"294":4,"316":6,"318":17,"319":24,"506":1,"527":6,"533":4}}],["dstr",{"2":{"38":8}}],["doresize",{"2":{"584":4}}],["dog",{"2":{"271":8,"272":2,"277":1,"409":8,"410":8,"411":2}}],["do",{"2":{"260":2}}],["done",{"2":{"243":6,"525":4}}],["does",{"2":{"235":1,"586":2}}],["doesn",{"2":{"36":2}}],["down",{"2":{"111":1,"112":1}}],["download",{"2":{"66":2}}],["domexception",{"2":{"551":2}}],["dom树和",{"2":{"459":1}}],["dom",{"0":{"560":2},"2":{"82":2,"109":2,"112":2,"129":2,"139":4,"141":2,"414":4,"431":5,"455":2,"456":2,"497":1,"560":8}}],["docsearch",{"2":{"603":6}}],["docs",{"2":{"395":4,"599":14}}],["doctype",{"2":{"303":2}}],["docheck",{"2":{"109":4}}],["docker0",{"2":{"62":2}}],["docker网络",{"0":{"62":1},"1":{"63":1,"64":1}}],["dockerfile构建时运行",{"2":{"61":2}}],["dockerfile",{"2":{"61":1}}],["docker容器端口",{"2":{"56":2}}],["docker",{"0":{"54":1},"2":{"51":18,"54":4,"55":20,"56":24,"57":2,"58":2,"59":6,"61":10,"62":12,"64":7,"66":6}}],["documentelement",{"2":{"614":2}}],["document",{"2":{"7":2,"113":2,"137":2,"139":2,"140":2,"143":2,"144":8,"145":2,"249":2,"250":2,"374":4,"457":2,"523":6,"536":2,"551":2,"574":12,"577":6,"584":6,"614":2}}],["d",{"2":{"16":2,"17":4,"56":2,"57":2,"62":4,"63":2,"64":8,"206":2,"207":4,"220":2,"268":8,"302":10,"340":2,"342":4,"344":4,"346":6,"350":2,"399":6,"417":2,"418":8,"422":1,"432":6,"439":1,"440":2,"570":1,"601":1}}],["dialog",{"2":{"609":4}}],["dialogregister",{"2":{"578":2}}],["diff",{"2":{"328":4}}],["difference",{"2":{"324":12}}],["digitize",{"2":{"373":6}}],["digitmap",{"2":{"302":2}}],["digit",{"2":{"268":6,"302":6}}],["div2",{"2":{"540":6}}],["div",{"2":{"104":12,"105":12,"106":4,"107":24,"108":4,"113":4,"114":32,"116":8,"119":4,"121":8,"123":8,"137":4,"139":4,"145":4,"151":4,"152":4,"153":4,"168":16,"170":16,"375":2,"457":1,"482":16,"551":8,"577":2,"583":4,"586":12,"587":8,"610":4,"615":1}}],["dirstr",{"2":{"599":8}}],["dir=dist",{"2":{"573":2}}],["dir=",{"2":{"573":2}}],["dirdata",{"2":{"357":6}}],["dirhandle",{"2":{"357":8}}],["directorydata",{"2":{"357":2}}],["directory",{"2":{"234":1,"357":2}}],["direction",{"2":{"180":2,"202":2,"615":4}}],["directives",{"2":{"554":1}}],["directive",{"2":{"125":4,"126":4,"574":2,"586":2}}],["dir就是上传文件存放的目录",{"2":{"46":2}}],["dir",{"2":{"46":8,"349":2,"357":4,"396":2,"599":20}}],["dirname+",{"2":{"16":12}}],["dirname",{"2":{"16":8,"22":8,"418":2,"599":10}}],["dirname输出是路径是",{"2":{"16":1}}],["dirname代表当前文件所处目录",{"2":{"16":1}}],["disconnect",{"2":{"615":2}}],["dispatchevent",{"2":{"584":4}}],["displaydns",{"2":{"450":1}}],["display",{"2":{"113":2,"164":2,"168":2,"170":2,"176":2,"177":2,"180":2,"189":2,"190":4,"202":2,"474":8,"482":2,"490":2,"551":2,"603":4}}],["disappearing",{"2":{"578":2}}],["disabled",{"2":{"86":2}}],["dist",{"2":{"357":2,"395":4,"396":2,"414":4,"418":2}}],["distinct",{"2":{"4":2}}],["diskstorage",{"2":{"46":2}}],["dealdata",{"2":{"577":4}}],["deactivated",{"2":{"559":1}}],["debounce",{"2":{"519":6,"577":4}}],["defineconfig",{"2":{"602":4}}],["definenuxtconfig",{"2":{"589":2}}],["defined",{"2":{"586":2}}],["defineproperty",{"2":{"512":2}}],["defaultcombo",{"2":{"577":2}}],["defaultchangedetection",{"2":{"111":1}}],["defaultedge",{"2":{"577":2}}],["defaultnode",{"2":{"577":2}}],["defaultprops",{"2":{"144":4}}],["default",{"2":{"13":14,"111":1,"114":14,"151":2,"152":2,"153":2,"156":2,"157":2,"259":2,"427":2,"440":2,"577":2,"585":2,"589":2,"599":2,"602":4,"610":4}}],["deltay",{"2":{"615":2}}],["delays",{"2":{"577":4}}],["delay\\t",{"2":{"519":2}}],["delay",{"2":{"493":12,"494":12,"519":16,"520":12,"577":4,"578":12}}],["deleteafterpage",{"2":{"159":6}}],["deletearticle",{"2":{"10":2}}],["deleted",{"2":{"38":2}}],["delete",{"2":{"9":2,"38":2,"206":2,"207":2,"265":2,"266":2,"296":6}}],["deletemany",{"2":{"6":2}}],["deleteone",{"2":{"6":2}}],["deprecated",{"2":{"584":2}}],["deploy",{"2":{"396":6}}],["depth",{"2":{"282":4,"396":2}}],["denied",{"2":{"234":2}}],["devproxy",{"2":{"589":2}}],["dev",{"2":{"417":2,"418":2}}],["dev分支后",{"2":{"205":1}}],["development",{"2":{"139":4}}],["deepgeneratesidebar",{"2":{"599":4}}],["deepgetfile",{"2":{"599":6}}],["deepclone",{"2":{"319":6,"527":4}}],["deeppink",{"2":{"183":2}}],["deep",{"2":{"158":2,"282":4,"611":2}}],["decimal",{"2":{"513":1}}],["decimalpipe",{"2":{"132":1}}],["declaration",{"2":{"440":2}}],["declarations",{"0":{"79":1},"2":{"78":1,"80":2}}],["decrcomponent",{"2":{"119":2}}],["decr",{"2":{"119":2}}],["dec",{"2":{"116":8}}],["detail",{"2":{"318":6,"319":10}}],["detach",{"2":{"112":2}}],["detected",{"2":{"311":2,"315":2}}],["detectchanges",{"2":{"112":3}}],["destoryed",{"2":{"555":2}}],["destory",{"2":{"113":2}}],["dest",{"2":{"61":2}}],["destination",{"2":{"46":2,"396":2}}],["destroy",{"2":{"42":2,"113":2,"577":2}}],["descriptions",{"2":{"609":12}}],["descriptionsitem",{"2":{"609":1}}],["descriptor",{"2":{"426":2}}],["descendants",{"2":{"106":3}}],["desc",{"2":{"11":2,"13":2}}],["demo",{"2":{"15":2,"137":1,"145":4}}],["dburi",{"2":{"13":4}}],["db",{"2":{"1":4,"2":6,"4":24,"5":10,"6":8,"7":7,"13":6,"34":4,"35":2,"36":4,"37":4,"38":4}}],["dbs",{"2":{"1":2}}],["二是",{"2":{"524":1}}],["二叉搜索树的插入和查找",{"0":{"300":1}}],["二叉树三种遍历方式",{"2":{"299":1}}],["二叉树的遍历",{"0":{"299":1}}],["二楞1",{"2":{"5":2}}],["二楞",{"2":{"5":2}}],["二",{"0":{"1":1,"18":1,"48":1,"83":1,"138":1,"304":1,"323":1,"327":1,"401":1,"406":1,"415":1,"451":1,"457":1,"580":1},"1":{"84":1,"85":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":1,"96":1,"139":1,"140":1,"141":1,"142":1,"143":1,"144":1,"145":1,"146":1,"147":1,"416":1,"417":1,"418":1,"419":1,"420":1,"421":1,"422":1,"423":1},"2":{"302":6}}],["高效做法",{"2":{"243":2}}],["高阶函数之",{"0":{"376":1,"386":1},"1":{"377":1,"378":1,"379":1,"380":1,"381":1,"382":1,"383":1,"384":1,"385":1,"387":1,"388":1,"389":1}}],["高阶函数之map",{"0":{"366":1},"1":{"367":1,"368":1,"369":1,"370":1,"371":1,"372":1,"373":1,"374":1,"375":1}}],["高阶函数之filter",{"0":{"358":1},"1":{"359":1,"360":1,"361":1,"362":1,"363":1,"364":1,"365":1}}],["高阶函数",{"2":{"146":1}}],["高可用性",{"2":{"0":1}}],["高性能",{"2":{"0":1}}],["一键复制",{"0":{"574":1}}],["一是",{"2":{"524":1}}],["一方面会导致繁忙的主线程白白的消耗时间",{"2":{"447":1}}],["一败涂地",{"2":{"303":2,"307":4,"308":2}}],["一十",{"2":{"302":2}}],["一修改就是修改所有实例的原型",{"2":{"275":1}}],["一些巧妙的技巧",{"2":{"181":1}}],["一定是数字运算",{"2":{"510":2}}],["一定会引起",{"2":{"466":1}}],["一定注意区分",{"2":{"137":1}}],["一定要在路由之前注册中间件",{"2":{"29":1}}],["一段组价默认的内容",{"2":{"114":4}}],["一段父组件传入的内容",{"2":{"114":4}}],["一段提示",{"2":{"113":2}}],["一段文字",{"2":{"91":2,"121":6}}],["一行文字",{"2":{"87":2}}],["一般来说",{"2":{"573":1}}],["一般我们都不会配置base属性",{"2":{"572":1}}],["一般会进行以下几步",{"2":{"450":1}}],["一般在这个钩子中做一些收尾的事",{"2":{"147":4}}],["一般在这个钩子中做一些初始化的事",{"2":{"147":4}}],["一般对象",{"2":{"137":1}}],["一般指定信号名",{"2":{"61":2}}],["一般语句为",{"2":{"61":2}}],["一次性删除多个再运行的",{"2":{"56":1}}],["一次性删除多个再运行的docker",{"2":{"56":1}}],["一次镜像",{"2":{"47":1}}],["一个没找到则返回",{"2":{"509":2}}],["一个进程中至少包含一个线程",{"2":{"443":1}}],["一个",{"2":{"347":2}}],["一个或多个",{"2":{"347":2}}],["一个表达式会产生一个值",{"2":{"137":1}}],["一个组件只能被一个模块声名",{"2":{"79":2}}],["一个镜像可以创建多个容器",{"2":{"49":1}}],["一个只读的模板",{"2":{"49":1}}],["一",{"0":{"0":1,"16":1,"47":1,"69":1,"77":1,"136":1,"159":1,"303":1,"322":1,"326":1,"398":1,"404":1,"414":1,"450":1,"456":1,"579":1},"1":{"17":1,"70":1,"71":1,"72":1,"78":1,"79":1,"80":1,"81":1,"82":1,"137":1,"399":1,"400":1,"405":1},"2":{"302":6}}]],"serializationVersion":2}';export{t as default}; diff --git a/assets/chunks/DemoWrap.1b6e7adf.js b/assets/chunks/DemoWrap.1b6e7adf.js new file mode 100644 index 00000000..9fe2df7e --- /dev/null +++ b/assets/chunks/DemoWrap.1b6e7adf.js @@ -0,0 +1 @@ +import{d,g as u,h as m,a7 as i,C as f,o as a,c as r,k,e as n,H as v,w as c,b as h,a as g,r as y,a8 as C,t as B,_ as b}from"./framework.c53372a0.js";const x={key:0,class:"demo-source-link"},D={key:1,class:"error"},$="https://github.com/fxzer/zerdocs/blob/master/docs",L=d({__name:"DemoWrap",props:{pkg:{},path:{}},setup(l){const e=l,t=u(()=>e.pkg&&e.path?`/${e.pkg}/${e.path}`:""),o=m(null);i(s=>{o.value=s});const p=`${$}${t.value}`;return(s,N)=>{const _=f("ClientOnly");return a(),r("div",{key:t.value,class:"demo wide"},[t.value?(a(),r("p",x,[k("a",{href:p,target:"_blank"},"源码地址")])):n("",!0),v(_,null,{default:c(()=>[(a(),h(C,null,{fallback:c(()=>[g(" Loading demo... ")]),default:c(()=>[y(s.$slots,"default",{},void 0,!0)]),_:3}))]),_:3}),o.value?(a(),r("div",D,B(o.value),1)):n("",!0)])}}});const w=b(L,[["__scopeId","data-v-9caf4c6f"]]);export{w as D}; diff --git a/assets/chunks/VPLocalSearchBox.0bede1e4.js b/assets/chunks/VPLocalSearchBox.0bede1e4.js new file mode 100644 index 00000000..7cbad3da --- /dev/null +++ b/assets/chunks/VPLocalSearchBox.0bede1e4.js @@ -0,0 +1,7 @@ +import{X as pt,h as ie,x as Be,ao as kt,ap as Nt,d as It,E as be,aq as et,g as we,ar as Dt,as as _t,y as Ot,at as Rt,j as De,O as de,V as xe,au as Mt,S as Lt,U as Pt,av as zt,Y as Bt,s as Vt,aw as $t,o as X,b as Wt,k as F,a1 as Kt,l as U,a4 as jt,a5 as Jt,ax as Ut,c as te,n as tt,e as Fe,D as rt,F as at,a as he,t as ve,ay as Ht,p as Gt,m as Qt,az as nt,aA as qt,ae as Yt,ak as Zt,_ as Xt}from"./framework.c53372a0.js";import{u as er,c as tr}from"./theme.1e9d2528.js";const rr={root:()=>pt(()=>import("./@localSearchIndexroot.20abec5d.js"),[])};/*! +* tabbable 6.2.0 +* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE +*/var yt=["input:not([inert])","select:not([inert])","textarea:not([inert])","a[href]:not([inert])","button:not([inert])","[tabindex]:not(slot):not([inert])","audio[controls]:not([inert])","video[controls]:not([inert])",'[contenteditable]:not([contenteditable="false"]):not([inert])',"details>summary:first-of-type:not([inert])","details:not([inert])"],Ae=yt.join(","),mt=typeof Element>"u",se=mt?function(){}:Element.prototype.matches||Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector,Ce=!mt&&Element.prototype.getRootNode?function(o){var e;return o==null||(e=o.getRootNode)===null||e===void 0?void 0:e.call(o)}:function(o){return o==null?void 0:o.ownerDocument},Te=function o(e,t){var r;t===void 0&&(t=!0);var n=e==null||(r=e.getAttribute)===null||r===void 0?void 0:r.call(e,"inert"),a=n===""||n==="true",i=a||t&&e&&o(e.parentNode);return i},ar=function(e){var t,r=e==null||(t=e.getAttribute)===null||t===void 0?void 0:t.call(e,"contenteditable");return r===""||r==="true"},gt=function(e,t,r){if(Te(e))return[];var n=Array.prototype.slice.apply(e.querySelectorAll(Ae));return t&&se.call(e,Ae)&&n.unshift(e),n=n.filter(r),n},bt=function o(e,t,r){for(var n=[],a=Array.from(e);a.length;){var i=a.shift();if(!Te(i,!1))if(i.tagName==="SLOT"){var s=i.assignedElements(),u=s.length?s:i.children,l=o(u,!0,r);r.flatten?n.push.apply(n,l):n.push({scopeParent:i,candidates:l})}else{var d=se.call(i,Ae);d&&r.filter(i)&&(t||!e.includes(i))&&n.push(i);var h=i.shadowRoot||typeof r.getShadowRoot=="function"&&r.getShadowRoot(i),v=!Te(h,!1)&&(!r.shadowRootFilter||r.shadowRootFilter(i));if(h&&v){var m=o(h===!0?i.children:h.children,!0,r);r.flatten?n.push.apply(n,m):n.push({scopeParent:i,candidates:m})}else a.unshift.apply(a,i.children)}}return n},wt=function(e){return!isNaN(parseInt(e.getAttribute("tabindex"),10))},oe=function(e){if(!e)throw new Error("No node provided");return e.tabIndex<0&&(/^(AUDIO|VIDEO|DETAILS)$/.test(e.tagName)||ar(e))&&!wt(e)?0:e.tabIndex},nr=function(e,t){var r=oe(e);return r<0&&t&&!wt(e)?0:r},ir=function(e,t){return e.tabIndex===t.tabIndex?e.documentOrder-t.documentOrder:e.tabIndex-t.tabIndex},xt=function(e){return e.tagName==="INPUT"},or=function(e){return xt(e)&&e.type==="hidden"},sr=function(e){var t=e.tagName==="DETAILS"&&Array.prototype.slice.apply(e.children).some(function(r){return r.tagName==="SUMMARY"});return t},ur=function(e,t){for(var r=0;rsummary:first-of-type"),i=a?e.parentElement:e;if(se.call(i,"details:not([open]) *"))return!0;if(!r||r==="full"||r==="legacy-full"){if(typeof n=="function"){for(var s=e;e;){var u=e.parentElement,l=Ce(e);if(u&&!u.shadowRoot&&n(u)===!0)return it(e);e.assignedSlot?e=e.assignedSlot:!u&&l!==e.ownerDocument?e=l.host:e=u}e=s}if(dr(e))return!e.getClientRects().length;if(r!=="legacy-full")return!0}else if(r==="non-zero-area")return it(e);return!1},vr=function(e){if(/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(e.tagName))for(var t=e.parentElement;t;){if(t.tagName==="FIELDSET"&&t.disabled){for(var r=0;r=0)},yr=function o(e){var t=[],r=[];return e.forEach(function(n,a){var i=!!n.scopeParent,s=i?n.scopeParent:n,u=nr(s,i),l=i?o(n.candidates):s;u===0?i?t.push.apply(t,l):t.push(s):r.push({documentOrder:a,tabIndex:u,item:n,isScope:i,content:l})}),r.sort(ir).reduce(function(n,a){return a.isScope?n.push.apply(n,a.content):n.push(a.content),n},[]).concat(t)},mr=function(e,t){t=t||{};var r;return t.getShadowRoot?r=bt([e],t.includeContainer,{filter:Ve.bind(null,t),flatten:!1,getShadowRoot:t.getShadowRoot,shadowRootFilter:pr}):r=gt(e,t.includeContainer,Ve.bind(null,t)),yr(r)},gr=function(e,t){t=t||{};var r;return t.getShadowRoot?r=bt([e],t.includeContainer,{filter:ke.bind(null,t),flatten:!0,getShadowRoot:t.getShadowRoot}):r=gt(e,t.includeContainer,ke.bind(null,t)),r},ue=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return se.call(e,Ae)===!1?!1:Ve(t,e)},br=yt.concat("iframe").join(","),_e=function(e,t){if(t=t||{},!e)throw new Error("No node provided");return se.call(e,br)===!1?!1:ke(t,e)};/*! +* focus-trap 7.5.4 +* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE +*/function ot(o,e){var t=Object.keys(o);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(o);e&&(r=r.filter(function(n){return Object.getOwnPropertyDescriptor(o,n).enumerable})),t.push.apply(t,r)}return t}function st(o){for(var e=1;e0){var r=e[e.length-1];r!==t&&r.pause()}var n=e.indexOf(t);n===-1||e.splice(n,1),e.push(t)},deactivateTrap:function(e,t){var r=e.indexOf(t);r!==-1&&e.splice(r,1),e.length>0&&e[e.length-1].unpause()}},Er=function(e){return e.tagName&&e.tagName.toLowerCase()==="input"&&typeof e.select=="function"},Sr=function(e){return(e==null?void 0:e.key)==="Escape"||(e==null?void 0:e.key)==="Esc"||(e==null?void 0:e.keyCode)===27},me=function(e){return(e==null?void 0:e.key)==="Tab"||(e==null?void 0:e.keyCode)===9},Ar=function(e){return me(e)&&!e.shiftKey},Cr=function(e){return me(e)&&e.shiftKey},lt=function(e){return setTimeout(e,0)},ct=function(e,t){var r=-1;return e.every(function(n,a){return t(n)?(r=a,!1):!0}),r},pe=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n1?p-1:0),k=1;k=0)c=r.activeElement;else{var f=i.tabbableGroups[0],p=f&&f.firstTabbableNode;c=p||d("fallbackFocus")}if(!c)throw new Error("Your focus-trap needs to have at least one focusable element");return c},v=function(){if(i.containerGroups=i.containers.map(function(c){var f=mr(c,a.tabbableOptions),p=gr(c,a.tabbableOptions),N=f.length>0?f[0]:void 0,k=f.length>0?f[f.length-1]:void 0,M=p.find(function(w){return ue(w)}),z=p.slice().reverse().find(function(w){return ue(w)}),y=!!f.find(function(w){return oe(w)>0});return{container:c,tabbableNodes:f,focusableNodes:p,posTabIndexesFound:y,firstTabbableNode:N,lastTabbableNode:k,firstDomTabbableNode:M,lastDomTabbableNode:z,nextTabbableNode:function(B){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,K=f.indexOf(B);return K<0?G?p.slice(p.indexOf(B)+1).find(function(j){return ue(j)}):p.slice(0,p.indexOf(B)).reverse().find(function(j){return ue(j)}):f[K+(G?1:-1)]}}}),i.tabbableGroups=i.containerGroups.filter(function(c){return c.tabbableNodes.length>0}),i.tabbableGroups.length<=0&&!d("fallbackFocus"))throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times");if(i.containerGroups.find(function(c){return c.posTabIndexesFound})&&i.containerGroups.length>1)throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.")},m=function x(c){var f=c.activeElement;if(f)return f.shadowRoot&&f.shadowRoot.activeElement!==null?x(f.shadowRoot):f},b=function x(c){if(c!==!1&&c!==m(document)){if(!c||!c.focus){x(h());return}c.focus({preventScroll:!!a.preventScroll}),i.mostRecentlyFocusedNode=c,Er(c)&&c.select()}},E=function(c){var f=d("setReturnFocus",c);return f||(f===!1?!1:c)},g=function(c){var f=c.target,p=c.event,N=c.isBackward,k=N===void 0?!1:N;f=f||Ee(p),v();var M=null;if(i.tabbableGroups.length>0){var z=l(f,p),y=z>=0?i.containerGroups[z]:void 0;if(z<0)k?M=i.tabbableGroups[i.tabbableGroups.length-1].lastTabbableNode:M=i.tabbableGroups[0].firstTabbableNode;else if(k){var w=ct(i.tabbableGroups,function(J){var Q=J.firstTabbableNode;return f===Q});if(w<0&&(y.container===f||_e(f,a.tabbableOptions)&&!ue(f,a.tabbableOptions)&&!y.nextTabbableNode(f,!1))&&(w=z),w>=0){var B=w===0?i.tabbableGroups.length-1:w-1,G=i.tabbableGroups[B];M=oe(f)>=0?G.lastTabbableNode:G.lastDomTabbableNode}else me(p)||(M=y.nextTabbableNode(f,!1))}else{var K=ct(i.tabbableGroups,function(J){var Q=J.lastTabbableNode;return f===Q});if(K<0&&(y.container===f||_e(f,a.tabbableOptions)&&!ue(f,a.tabbableOptions)&&!y.nextTabbableNode(f))&&(K=z),K>=0){var j=K===i.tabbableGroups.length-1?0:K+1,V=i.tabbableGroups[j];M=oe(f)>=0?V.firstTabbableNode:V.firstDomTabbableNode}else me(p)||(M=y.nextTabbableNode(f))}}else M=d("fallbackFocus");return M},S=function(c){var f=Ee(c);if(!(l(f,c)>=0)){if(pe(a.clickOutsideDeactivates,c)){s.deactivate({returnFocus:a.returnFocusOnDeactivate});return}pe(a.allowOutsideClick,c)||c.preventDefault()}},T=function(c){var f=Ee(c),p=l(f,c)>=0;if(p||f instanceof Document)p&&(i.mostRecentlyFocusedNode=f);else{c.stopImmediatePropagation();var N,k=!0;if(i.mostRecentlyFocusedNode)if(oe(i.mostRecentlyFocusedNode)>0){var M=l(i.mostRecentlyFocusedNode),z=i.containerGroups[M].tabbableNodes;if(z.length>0){var y=z.findIndex(function(w){return w===i.mostRecentlyFocusedNode});y>=0&&(a.isKeyForward(i.recentNavEvent)?y+1=0&&(N=z[y-1],k=!1))}}else i.containerGroups.some(function(w){return w.tabbableNodes.some(function(B){return oe(B)>0})})||(k=!1);else k=!1;k&&(N=g({target:i.mostRecentlyFocusedNode,isBackward:a.isKeyBackward(i.recentNavEvent)})),b(N||i.mostRecentlyFocusedNode||h())}i.recentNavEvent=void 0},C=function(c){var f=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;i.recentNavEvent=c;var p=g({event:c,isBackward:f});p&&(me(c)&&c.preventDefault(),b(p))},R=function(c){if(Sr(c)&&pe(a.escapeDeactivates,c)!==!1){c.preventDefault(),s.deactivate();return}(a.isKeyForward(c)||a.isKeyBackward(c))&&C(c,a.isKeyBackward(c))},L=function(c){var f=Ee(c);l(f,c)>=0||pe(a.clickOutsideDeactivates,c)||pe(a.allowOutsideClick,c)||(c.preventDefault(),c.stopImmediatePropagation())},P=function(){if(i.active)return ut.activateTrap(n,s),i.delayInitialFocusTimer=a.delayInitialFocus?lt(function(){b(h())}):b(h()),r.addEventListener("focusin",T,!0),r.addEventListener("mousedown",S,{capture:!0,passive:!1}),r.addEventListener("touchstart",S,{capture:!0,passive:!1}),r.addEventListener("click",L,{capture:!0,passive:!1}),r.addEventListener("keydown",R,{capture:!0,passive:!1}),s},I=function(){if(i.active)return r.removeEventListener("focusin",T,!0),r.removeEventListener("mousedown",S,!0),r.removeEventListener("touchstart",S,!0),r.removeEventListener("click",L,!0),r.removeEventListener("keydown",R,!0),s},A=function(c){var f=c.some(function(p){var N=Array.from(p.removedNodes);return N.some(function(k){return k===i.mostRecentlyFocusedNode})});f&&b(h())},_=typeof window<"u"&&"MutationObserver"in window?new MutationObserver(A):void 0,O=function(){_&&(_.disconnect(),i.active&&!i.paused&&i.containers.map(function(c){_.observe(c,{subtree:!0,childList:!0})}))};return s={get active(){return i.active},get paused(){return i.paused},activate:function(c){if(i.active)return this;var f=u(c,"onActivate"),p=u(c,"onPostActivate"),N=u(c,"checkCanFocusTrap");N||v(),i.active=!0,i.paused=!1,i.nodeFocusedBeforeActivation=r.activeElement,f==null||f();var k=function(){N&&v(),P(),O(),p==null||p()};return N?(N(i.containers.concat()).then(k,k),this):(k(),this)},deactivate:function(c){if(!i.active)return this;var f=st({onDeactivate:a.onDeactivate,onPostDeactivate:a.onPostDeactivate,checkCanReturnFocus:a.checkCanReturnFocus},c);clearTimeout(i.delayInitialFocusTimer),i.delayInitialFocusTimer=void 0,I(),i.active=!1,i.paused=!1,O(),ut.deactivateTrap(n,s);var p=u(f,"onDeactivate"),N=u(f,"onPostDeactivate"),k=u(f,"checkCanReturnFocus"),M=u(f,"returnFocus","returnFocusOnDeactivate");p==null||p();var z=function(){lt(function(){M&&b(E(i.nodeFocusedBeforeActivation)),N==null||N()})};return M&&k?(k(E(i.nodeFocusedBeforeActivation)).then(z,z),this):(z(),this)},pause:function(c){if(i.paused||!i.active)return this;var f=u(c,"onPause"),p=u(c,"onPostPause");return i.paused=!0,f==null||f(),I(),O(),p==null||p(),this},unpause:function(c){if(!i.paused||!i.active)return this;var f=u(c,"onUnpause"),p=u(c,"onPostUnpause");return i.paused=!1,f==null||f(),v(),P(),O(),p==null||p(),this},updateContainerElements:function(c){var f=[].concat(c).filter(Boolean);return i.containers=f.map(function(p){return typeof p=="string"?r.querySelector(p):p}),i.active&&v(),O(),this}},s.updateContainerElements(e),s};function Nr(o,e={}){let t;const{immediate:r,...n}=e,a=ie(!1),i=ie(!1),s=h=>t&&t.activate(h),u=h=>t&&t.deactivate(h),l=()=>{t&&(t.pause(),i.value=!0)},d=()=>{t&&(t.unpause(),i.value=!1)};return Be(()=>kt(o),h=>{h&&(t=kr(h,{...n,onActivate(){a.value=!0,e.onActivate&&e.onActivate()},onDeactivate(){a.value=!1,e.onDeactivate&&e.onDeactivate()}}),r&&s())},{flush:"post"}),Nt(()=>u()),{hasFocus:a,isPaused:i,activate:s,deactivate:u,pause:l,unpause:d}}class ce{constructor(e,t=!0,r=[],n=5e3){this.ctx=e,this.iframes=t,this.exclude=r,this.iframesTimeout=n}static matches(e,t){const r=typeof t=="string"?[t]:t,n=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(n){let a=!1;return r.every(i=>n.call(e,i)?(a=!0,!1):!0),a}else return!1}getContexts(){let e,t=[];return typeof this.ctx>"u"||!this.ctx?e=[]:NodeList.prototype.isPrototypeOf(this.ctx)?e=Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?e=this.ctx:typeof this.ctx=="string"?e=Array.prototype.slice.call(document.querySelectorAll(this.ctx)):e=[this.ctx],e.forEach(r=>{const n=t.filter(a=>a.contains(r)).length>0;t.indexOf(r)===-1&&!n&&t.push(r)}),t}getIframeContents(e,t,r=()=>{}){let n;try{const a=e.contentWindow;if(n=a.document,!a||!n)throw new Error("iframe inaccessible")}catch{r()}n&&t(n)}isIframeBlank(e){const t="about:blank",r=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&r!==t&&r}observeIframeLoad(e,t,r){let n=!1,a=null;const i=()=>{if(!n){n=!0,clearTimeout(a);try{this.isIframeBlank(e)||(e.removeEventListener("load",i),this.getIframeContents(e,t,r))}catch{r()}}};e.addEventListener("load",i),a=setTimeout(i,this.iframesTimeout)}onIframeReady(e,t,r){try{e.contentWindow.document.readyState==="complete"?this.isIframeBlank(e)?this.observeIframeLoad(e,t,r):this.getIframeContents(e,t,r):this.observeIframeLoad(e,t,r)}catch{r()}}waitForIframes(e,t){let r=0;this.forEachIframe(e,()=>!0,n=>{r++,this.waitForIframes(n.querySelector("html"),()=>{--r||t()})},n=>{n||t()})}forEachIframe(e,t,r,n=()=>{}){let a=e.querySelectorAll("iframe"),i=a.length,s=0;a=Array.prototype.slice.call(a);const u=()=>{--i<=0&&n(s)};i||u(),a.forEach(l=>{ce.matches(l,this.exclude)?u():this.onIframeReady(l,d=>{t(l)&&(s++,r(d)),u()},u)})}createIterator(e,t,r){return document.createNodeIterator(e,t,r,!1)}createInstanceOnIframe(e){return new ce(e.querySelector("html"),this.iframes)}compareNodeIframe(e,t,r){const n=e.compareDocumentPosition(r),a=Node.DOCUMENT_POSITION_PRECEDING;if(n&a)if(t!==null){const i=t.compareDocumentPosition(r),s=Node.DOCUMENT_POSITION_FOLLOWING;if(i&s)return!0}else return!0;return!1}getIteratorNode(e){const t=e.previousNode();let r;return t===null?r=e.nextNode():r=e.nextNode()&&e.nextNode(),{prevNode:t,node:r}}checkIframeFilter(e,t,r,n){let a=!1,i=!1;return n.forEach((s,u)=>{s.val===r&&(a=u,i=s.handled)}),this.compareNodeIframe(e,t,r)?(a===!1&&!i?n.push({val:r,handled:!0}):a!==!1&&!i&&(n[a].handled=!0),!0):(a===!1&&n.push({val:r,handled:!1}),!1)}handleOpenIframes(e,t,r,n){e.forEach(a=>{a.handled||this.getIframeContents(a.val,i=>{this.createInstanceOnIframe(i).forEachNode(t,r,n)})})}iterateThroughNodes(e,t,r,n,a){const i=this.createIterator(t,e,n);let s=[],u=[],l,d,h=()=>({prevNode:d,node:l}=this.getIteratorNode(i),l);for(;h();)this.iframes&&this.forEachIframe(t,v=>this.checkIframeFilter(l,d,v,s),v=>{this.createInstanceOnIframe(v).forEachNode(e,m=>u.push(m),n)}),u.push(l);u.forEach(v=>{r(v)}),this.iframes&&this.handleOpenIframes(s,e,r,n),a()}forEachNode(e,t,r,n=()=>{}){const a=this.getContexts();let i=a.length;i||n(),a.forEach(s=>{const u=()=>{this.iterateThroughNodes(e,s,t,r,()=>{--i<=0&&n()})};this.iframes?this.waitForIframes(s,u):u()})}}let Ir=class{constructor(e){this.ctx=e,this.ie=!1;const t=window.navigator.userAgent;(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(this.ie=!0)}set opt(e){this._opt=Object.assign({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:()=>{},noMatch:()=>{},filter:()=>!0,done:()=>{},debug:!1,log:window.console},e)}get opt(){return this._opt}get iterator(){return new ce(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}log(e,t="debug"){const r=this.opt.log;this.opt.debug&&typeof r=="object"&&typeof r[t]=="function"&&r[t](`mark.js: ${e}`)}escapeStr(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}createRegExp(e){return this.opt.wildcards!=="disabled"&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),this.opt.wildcards!=="disabled"&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),e}createSynonymsRegExp(e){const t=this.opt.synonyms,r=this.opt.caseSensitive?"":"i",n=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(let a in t)if(t.hasOwnProperty(a)){const i=t[a],s=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(a):this.escapeStr(a),u=this.opt.wildcards!=="disabled"?this.setupWildcardsRegExp(i):this.escapeStr(i);s!==""&&u!==""&&(e=e.replace(new RegExp(`(${this.escapeStr(s)}|${this.escapeStr(u)})`,`gm${r}`),n+`(${this.processSynomyms(s)}|${this.processSynomyms(u)})`+n))}return e}processSynomyms(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}setupWildcardsRegExp(e){return e=e.replace(/(?:\\)*\?/g,t=>t.charAt(0)==="\\"?"?":""),e.replace(/(?:\\)*\*/g,t=>t.charAt(0)==="\\"?"*":"")}createWildcardsRegExp(e){let t=this.opt.wildcards==="withSpaces";return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}setupIgnoreJoinersRegExp(e){return e.replace(/[^(|)\\]/g,(t,r,n)=>{let a=n.charAt(r+1);return/[(|)\\]/.test(a)||a===""?t:t+"\0"})}createJoinersRegExp(e){let t=[];const r=this.opt.ignorePunctuation;return Array.isArray(r)&&r.length&&t.push(this.escapeStr(r.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join(`[${t.join("")}]*`):e}createDiacriticsRegExp(e){const t=this.opt.caseSensitive?"":"i",r=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"];let n=[];return e.split("").forEach(a=>{r.every(i=>{if(i.indexOf(a)!==-1){if(n.indexOf(i)>-1)return!1;e=e.replace(new RegExp(`[${i}]`,`gm${t}`),`[${i}]`),n.push(i)}return!0})}),e}createMergedBlanksRegExp(e){return e.replace(/[\s]+/gmi,"[\\s]+")}createAccuracyRegExp(e){const t="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿";let r=this.opt.accuracy,n=typeof r=="string"?r:r.value,a=typeof r=="string"?[]:r.limiters,i="";switch(a.forEach(s=>{i+=`|${this.escapeStr(s)}`}),n){case"partially":default:return`()(${e})`;case"complementary":return i="\\s"+(i||this.escapeStr(t)),`()([^${i}]*${e}[^${i}]*)`;case"exactly":return`(^|\\s${i})(${e})(?=$|\\s${i})`}}getSeparatedKeywords(e){let t=[];return e.forEach(r=>{this.opt.separateWordSearch?r.split(" ").forEach(n=>{n.trim()&&t.indexOf(n)===-1&&t.push(n)}):r.trim()&&t.indexOf(r)===-1&&t.push(r)}),{keywords:t.sort((r,n)=>n.length-r.length),length:t.length}}isNumeric(e){return Number(parseFloat(e))==e}checkRanges(e){if(!Array.isArray(e)||Object.prototype.toString.call(e[0])!=="[object Object]")return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];const t=[];let r=0;return e.sort((n,a)=>n.start-a.start).forEach(n=>{let{start:a,end:i,valid:s}=this.callNoMatchOnInvalidRanges(n,r);s&&(n.start=a,n.length=i-a,t.push(n),r=i)}),t}callNoMatchOnInvalidRanges(e,t){let r,n,a=!1;return e&&typeof e.start<"u"?(r=parseInt(e.start,10),n=r+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&n-t>0&&n-r>0?a=!0:(this.log(`Ignoring invalid or overlapping range: ${JSON.stringify(e)}`),this.opt.noMatch(e))):(this.log(`Ignoring invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)),{start:r,end:n,valid:a}}checkWhitespaceRanges(e,t,r){let n,a=!0,i=r.length,s=t-i,u=parseInt(e.start,10)-s;return u=u>i?i:u,n=u+parseInt(e.length,10),n>i&&(n=i,this.log(`End range automatically set to the max value of ${i}`)),u<0||n-u<0||u>i||n>i?(a=!1,this.log(`Invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)):r.substring(u,n).replace(/\s+/g,"")===""&&(a=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:u,end:n,valid:a}}getTextNodes(e){let t="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,n=>{r.push({start:t.length,end:(t+=n.textContent).length,node:n})},n=>this.matchesExclude(n.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT,()=>{e({value:t,nodes:r})})}matchesExclude(e){return ce.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}wrapRangeInTextNode(e,t,r){const n=this.opt.element?this.opt.element:"mark",a=e.splitText(t),i=a.splitText(r-t);let s=document.createElement(n);return s.setAttribute("data-markjs","true"),this.opt.className&&s.setAttribute("class",this.opt.className),s.textContent=a.textContent,a.parentNode.replaceChild(s,a),i}wrapRangeInMappedTextNode(e,t,r,n,a){e.nodes.every((i,s)=>{const u=e.nodes[s+1];if(typeof u>"u"||u.start>t){if(!n(i.node))return!1;const l=t-i.start,d=(r>i.end?i.end:r)-i.start,h=e.value.substr(0,i.start),v=e.value.substr(d+i.start);if(i.node=this.wrapRangeInTextNode(i.node,l,d),e.value=h+v,e.nodes.forEach((m,b)=>{b>=s&&(e.nodes[b].start>0&&b!==s&&(e.nodes[b].start-=d),e.nodes[b].end-=d)}),r-=d,a(i.node.previousSibling,i.start),r>i.end)t=i.end;else return!1}return!0})}wrapMatches(e,t,r,n,a){const i=t===0?0:t+1;this.getTextNodes(s=>{s.nodes.forEach(u=>{u=u.node;let l;for(;(l=e.exec(u.textContent))!==null&&l[i]!=="";){if(!r(l[i],u))continue;let d=l.index;if(i!==0)for(let h=1;h{let u;for(;(u=e.exec(s.value))!==null&&u[i]!=="";){let l=u.index;if(i!==0)for(let h=1;hr(u[i],h),(h,v)=>{e.lastIndex=v,n(h)})}a()})}wrapRangeFromIndex(e,t,r,n){this.getTextNodes(a=>{const i=a.value.length;e.forEach((s,u)=>{let{start:l,end:d,valid:h}=this.checkWhitespaceRanges(s,i,a.value);h&&this.wrapRangeInMappedTextNode(a,l,d,v=>t(v,s,a.value.substring(l,d),u),v=>{r(v,s)})}),n()})}unwrapMatches(e){const t=e.parentNode;let r=document.createDocumentFragment();for(;e.firstChild;)r.appendChild(e.removeChild(e.firstChild));t.replaceChild(r,e),this.ie?this.normalizeTextNode(t):t.normalize()}normalizeTextNode(e){if(e){if(e.nodeType===3)for(;e.nextSibling&&e.nextSibling.nodeType===3;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}markRegExp(e,t){this.opt=t,this.log(`Searching with expression "${e}"`);let r=0,n="wrapMatches";const a=i=>{r++,this.opt.each(i)};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),this[n](e,this.opt.ignoreGroups,(i,s)=>this.opt.filter(s,i,r),a,()=>{r===0&&this.opt.noMatch(e),this.opt.done(r)})}mark(e,t){this.opt=t;let r=0,n="wrapMatches";const{keywords:a,length:i}=this.getSeparatedKeywords(typeof e=="string"?[e]:e),s=this.opt.caseSensitive?"":"i",u=l=>{let d=new RegExp(this.createRegExp(l),`gm${s}`),h=0;this.log(`Searching with expression "${d}"`),this[n](d,1,(v,m)=>this.opt.filter(m,l,r,h),v=>{h++,r++,this.opt.each(v)},()=>{h===0&&this.opt.noMatch(l),a[i-1]===l?this.opt.done(r):u(a[a.indexOf(l)+1])})};this.opt.acrossElements&&(n="wrapMatchesAcrossElements"),i===0?this.opt.done(r):u(a[0])}markRanges(e,t){this.opt=t;let r=0,n=this.checkRanges(e);n&&n.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(n)),this.wrapRangeFromIndex(n,(a,i,s,u)=>this.opt.filter(a,i,s,u),(a,i)=>{r++,this.opt.each(a,i)},()=>{this.opt.done(r)})):this.opt.done(r)}unmark(e){this.opt=e;let t=this.opt.element?this.opt.element:"*";t+="[data-markjs]",this.opt.className&&(t+=`.${this.opt.className}`),this.log(`Removal selector "${t}"`),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,r=>{this.unwrapMatches(r)},r=>{const n=ce.matches(r,t),a=this.matchesExclude(r);return!n||a?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}};function Dr(o){const e=new Ir(o);return this.mark=(t,r)=>(e.mark(t,r),this),this.markRegExp=(t,r)=>(e.markRegExp(t,r),this),this.markRanges=(t,r)=>(e.markRanges(t,r),this),this.unmark=t=>(e.unmark(t),this),this}var $=function(){return $=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0&&a[a.length-1])&&(l[0]===6||l[0]===2)){t=0;continue}if(l[0]===3&&(!a||l[1]>a[0]&&l[1]=o.length&&(o=void 0),{value:o&&o[r++],done:!o}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(o,e){var t=typeof Symbol=="function"&&o[Symbol.iterator];if(!t)return o;var r=t.call(o),n,a=[],i;try{for(;(e===void 0||e-- >0)&&!(n=r.next()).done;)a.push(n.value)}catch(s){i={error:s}}finally{try{n&&!n.done&&(t=r.return)&&t.call(r)}finally{if(i)throw i.error}}return a}var Rr="ENTRIES",Ft="KEYS",Et="VALUES",H="",Oe=function(){function o(e,t){var r=e._tree,n=Array.from(r.keys());this.set=e,this._type=t,this._path=n.length>0?[{node:r,keys:n}]:[]}return o.prototype.next=function(){var e=this.dive();return this.backtrack(),e},o.prototype.dive=function(){if(this._path.length===0)return{done:!0,value:void 0};var e=le(this._path),t=e.node,r=e.keys;if(le(r)===H)return{done:!1,value:this.result()};var n=t.get(le(r));return this._path.push({node:n,keys:Array.from(n.keys())}),this.dive()},o.prototype.backtrack=function(){if(this._path.length!==0){var e=le(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack())}},o.prototype.key=function(){return this.set._prefix+this._path.map(function(e){var t=e.keys;return le(t)}).filter(function(e){return e!==H}).join("")},o.prototype.value=function(){return le(this._path).node.get(H)},o.prototype.result=function(){switch(this._type){case Et:return this.value();case Ft:return this.key();default:return[this.key(),this.value()]}},o.prototype[Symbol.iterator]=function(){return this},o}(),le=function(o){return o[o.length-1]},Mr=function(o,e,t){var r=new Map;if(e===void 0)return r;for(var n=e.length+1,a=n+t,i=new Uint8Array(a*n).fill(t+1),s=0;st)continue e}St(o.get(m),e,t,r,n,E,i,s+m)}}}catch(f){u={error:f}}finally{try{v&&!v.done&&(l=h.return)&&l.call(h)}finally{if(u)throw u.error}}},Re=function(){function o(e,t){e===void 0&&(e=new Map),t===void 0&&(t=""),this._size=void 0,this._tree=e,this._prefix=t}return o.prototype.atPrefix=function(e){var t,r;if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");var n=W(Ne(this._tree,e.slice(this._prefix.length)),2),a=n[0],i=n[1];if(a===void 0){var s=W(je(i),2),u=s[0],l=s[1];try{for(var d=D(u.keys()),h=d.next();!h.done;h=d.next()){var v=h.value;if(v!==H&&v.startsWith(l)){var m=new Map;return m.set(v.slice(l.length),u.get(v)),new o(m,e)}}}catch(b){t={error:b}}finally{try{h&&!h.done&&(r=d.return)&&r.call(d)}finally{if(t)throw t.error}}}return new o(a,e)},o.prototype.clear=function(){this._size=void 0,this._tree.clear()},o.prototype.delete=function(e){return this._size=void 0,Lr(this._tree,e)},o.prototype.entries=function(){return new Oe(this,Rr)},o.prototype.forEach=function(e){var t,r;try{for(var n=D(this),a=n.next();!a.done;a=n.next()){var i=W(a.value,2),s=i[0],u=i[1];e(s,u,this)}}catch(l){t={error:l}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(t)throw t.error}}},o.prototype.fuzzyGet=function(e,t){return Mr(this._tree,e,t)},o.prototype.get=function(e){var t=$e(this._tree,e);return t!==void 0?t.get(H):void 0},o.prototype.has=function(e){var t=$e(this._tree,e);return t!==void 0&&t.has(H)},o.prototype.keys=function(){return new Oe(this,Ft)},o.prototype.set=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Me(this._tree,e);return r.set(H,t),this},Object.defineProperty(o.prototype,"size",{get:function(){if(this._size)return this._size;this._size=0;for(var e=this.entries();!e.next().done;)this._size+=1;return this._size},enumerable:!1,configurable:!0}),o.prototype.update=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Me(this._tree,e);return r.set(H,t(r.get(H))),this},o.prototype.fetch=function(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;var r=Me(this._tree,e),n=r.get(H);return n===void 0&&r.set(H,n=t()),n},o.prototype.values=function(){return new Oe(this,Et)},o.prototype[Symbol.iterator]=function(){return this.entries()},o.from=function(e){var t,r,n=new o;try{for(var a=D(e),i=a.next();!i.done;i=a.next()){var s=W(i.value,2),u=s[0],l=s[1];n.set(u,l)}}catch(d){t={error:d}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}return n},o.fromObject=function(e){return o.from(Object.entries(e))},o}(),Ne=function(o,e,t){var r,n;if(t===void 0&&(t=[]),e.length===0||o==null)return[o,t];try{for(var a=D(o.keys()),i=a.next();!i.done;i=a.next()){var s=i.value;if(s!==H&&e.startsWith(s))return t.push([o,s]),Ne(o.get(s),e.slice(s.length),t)}}catch(u){r={error:u}}finally{try{i&&!i.done&&(n=a.return)&&n.call(a)}finally{if(r)throw r.error}}return t.push([o,e]),Ne(void 0,"",t)},$e=function(o,e){var t,r;if(e.length===0||o==null)return o;try{for(var n=D(o.keys()),a=n.next();!a.done;a=n.next()){var i=a.value;if(i!==H&&e.startsWith(i))return $e(o.get(i),e.slice(i.length))}}catch(s){t={error:s}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(t)throw t.error}}},Me=function(o,e){var t,r,n=e.length;e:for(var a=0;o&&a0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new Re,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}},o.prototype.discard=function(e){var t=this,r=this._idToShortId.get(e);if(r==null)throw new Error("MiniSearch: cannot discard document with ID ".concat(e,": it is not in the index"));this._idToShortId.delete(e),this._documentIds.delete(r),this._storedFields.delete(r),(this._fieldLength.get(r)||[]).forEach(function(n,a){t.removeFieldLength(r,a,t._documentCount,n)}),this._fieldLength.delete(r),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()},o.prototype.maybeAutoVacuum=function(){if(this._options.autoVacuum!==!1){var e=this._options.autoVacuum,t=e.minDirtFactor,r=e.minDirtCount,n=e.batchSize,a=e.batchWait;this.conditionalVacuum({batchSize:n,batchWait:a},{minDirtCount:r,minDirtFactor:t})}},o.prototype.discardAll=function(e){var t,r,n=this._options.autoVacuum;try{this._options.autoVacuum=!1;try{for(var a=D(e),i=a.next();!i.done;i=a.next()){var s=i.value;this.discard(s)}}catch(u){t={error:u}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}}finally{this._options.autoVacuum=n}this.maybeAutoVacuum()},o.prototype.replace=function(e){var t=this._options,r=t.idField,n=t.extractField,a=n(e,r);this.discard(a),this.add(e)},o.prototype.vacuum=function(e){return e===void 0&&(e={}),this.conditionalVacuum(e)},o.prototype.conditionalVacuum=function(e,t){var r=this;return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&t,this._enqueuedVacuum!=null?this._enqueuedVacuum:(this._enqueuedVacuum=this._currentVacuum.then(function(){var n=r._enqueuedVacuumConditions;return r._enqueuedVacuumConditions=Ke,r.performVacuuming(e,n)}),this._enqueuedVacuum)):this.vacuumConditionsMet(t)===!1?Promise.resolve():(this._currentVacuum=this.performVacuuming(e),this._currentVacuum)},o.prototype.performVacuuming=function(e,t){return _r(this,void 0,void 0,function(){var r,n,a,i,s,u,l,d,h,v,m,b,E,g,S,T,C,R,L,P,I,A,_,O,x;return Or(this,function(c){switch(c.label){case 0:if(r=this._dirtCount,!this.vacuumConditionsMet(t))return[3,10];n=e.batchSize||We.batchSize,a=e.batchWait||We.batchWait,i=1,c.label=1;case 1:c.trys.push([1,7,8,9]),s=D(this._index),u=s.next(),c.label=2;case 2:if(u.done)return[3,6];l=W(u.value,2),d=l[0],h=l[1];try{for(v=(A=void 0,D(h)),m=v.next();!m.done;m=v.next()){b=W(m.value,2),E=b[0],g=b[1];try{for(S=(O=void 0,D(g)),T=S.next();!T.done;T=S.next())C=W(T.value,1),R=C[0],!this._documentIds.has(R)&&(g.size<=1?h.delete(E):g.delete(R))}catch(f){O={error:f}}finally{try{T&&!T.done&&(x=S.return)&&x.call(S)}finally{if(O)throw O.error}}}}catch(f){A={error:f}}finally{try{m&&!m.done&&(_=v.return)&&_.call(v)}finally{if(A)throw A.error}}return this._index.get(d).size===0&&this._index.delete(d),i%n!==0?[3,4]:[4,new Promise(function(f){return setTimeout(f,a)})];case 3:c.sent(),c.label=4;case 4:i+=1,c.label=5;case 5:return u=s.next(),[3,2];case 6:return[3,9];case 7:return L=c.sent(),P={error:L},[3,9];case 8:try{u&&!u.done&&(I=s.return)&&I.call(s)}finally{if(P)throw P.error}return[7];case 9:this._dirtCount-=r,c.label=10;case 10:return[4,null];case 11:return c.sent(),this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null,[2]}})})},o.prototype.vacuumConditionsMet=function(e){if(e==null)return!0;var t=e.minDirtCount,r=e.minDirtFactor;return t=t||ze.minDirtCount,r=r||ze.minDirtFactor,this.dirtCount>=t&&this.dirtFactor>=r},Object.defineProperty(o.prototype,"isVacuuming",{get:function(){return this._currentVacuum!=null},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"dirtCount",{get:function(){return this._dirtCount},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"dirtFactor",{get:function(){return this._dirtCount/(1+this._documentCount+this._dirtCount)},enumerable:!1,configurable:!0}),o.prototype.has=function(e){return this._idToShortId.has(e)},o.prototype.getStoredFields=function(e){var t=this._idToShortId.get(e);if(t!=null)return this._storedFields.get(t)},o.prototype.search=function(e,t){var r,n;t===void 0&&(t={});var a=this.executeQuery(e,t),i=[];try{for(var s=D(a),u=s.next();!u.done;u=s.next()){var l=W(u.value,2),d=l[0],h=l[1],v=h.score,m=h.terms,b=h.match,E=m.length||1,g={id:this._documentIds.get(d),score:v*E,terms:Object.keys(b),match:b};Object.assign(g,this._storedFields.get(d)),(t.filter==null||t.filter(g))&&i.push(g)}}catch(S){r={error:S}}finally{try{u&&!u.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}return e===o.wildcard&&t.boostDocument==null&&this._options.searchOptions.boostDocument==null||i.sort(ht),i},o.prototype.autoSuggest=function(e,t){var r,n,a,i;t===void 0&&(t={}),t=$($({},this._options.autoSuggestOptions),t);var s=new Map;try{for(var u=D(this.search(e,t)),l=u.next();!l.done;l=u.next()){var d=l.value,h=d.score,v=d.terms,m=v.join(" "),b=s.get(m);b!=null?(b.score+=h,b.count+=1):s.set(m,{score:h,terms:v,count:1})}}catch(L){r={error:L}}finally{try{l&&!l.done&&(n=u.return)&&n.call(u)}finally{if(r)throw r.error}}var E=[];try{for(var g=D(s),S=g.next();!S.done;S=g.next()){var T=W(S.value,2),b=T[0],C=T[1],h=C.score,v=C.terms,R=C.count;E.push({suggestion:b,terms:v,score:h/R})}}catch(L){a={error:L}}finally{try{S&&!S.done&&(i=g.return)&&i.call(g)}finally{if(a)throw a.error}}return E.sort(ht),E},Object.defineProperty(o.prototype,"documentCount",{get:function(){return this._documentCount},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"termCount",{get:function(){return this._index.size},enumerable:!1,configurable:!0}),o.loadJSON=function(e,t){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(e),t)},o.getDefault=function(e){if(Pe.hasOwnProperty(e))return Le(Pe,e);throw new Error('MiniSearch: unknown option "'.concat(e,'"'))},o.loadJS=function(e,t){var r,n,a,i,s,u,l=e.index,d=e.documentCount,h=e.nextId,v=e.documentIds,m=e.fieldIds,b=e.fieldLength,E=e.averageFieldLength,g=e.storedFields,S=e.dirtCount,T=e.serializationVersion;if(T!==1&&T!==2)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");var C=new o(t);C._documentCount=d,C._nextId=h,C._documentIds=Se(v),C._idToShortId=new Map,C._fieldIds=m,C._fieldLength=Se(b),C._avgFieldLength=E,C._storedFields=Se(g),C._dirtCount=S||0,C._index=new Re;try{for(var R=D(C._documentIds),L=R.next();!L.done;L=R.next()){var P=W(L.value,2),I=P[0],A=P[1];C._idToShortId.set(A,I)}}catch(y){r={error:y}}finally{try{L&&!L.done&&(n=R.return)&&n.call(R)}finally{if(r)throw r.error}}try{for(var _=D(l),O=_.next();!O.done;O=_.next()){var x=W(O.value,2),c=x[0],f=x[1],p=new Map;try{for(var N=(s=void 0,D(Object.keys(f))),k=N.next();!k.done;k=N.next()){var M=k.value,z=f[M];T===1&&(z=z.ds),p.set(parseInt(M,10),Se(z))}}catch(y){s={error:y}}finally{try{k&&!k.done&&(u=N.return)&&u.call(N)}finally{if(s)throw s.error}}C._index.set(c,p)}}catch(y){a={error:y}}finally{try{O&&!O.done&&(i=_.return)&&i.call(_)}finally{if(a)throw a.error}}return C},o.prototype.executeQuery=function(e,t){var r=this;if(t===void 0&&(t={}),e===o.wildcard)return this.executeWildcardQuery(t);if(typeof e!="string"){var n=$($($({},t),e),{queries:void 0}),a=e.queries.map(function(g){return r.executeQuery(g,n)});return this.combineResults(a,n.combineWith)}var i=this._options,s=i.tokenize,u=i.processTerm,l=i.searchOptions,d=$($({tokenize:s,processTerm:u},l),t),h=d.tokenize,v=d.processTerm,m=h(e).flatMap(function(g){return v(g)}).filter(function(g){return!!g}),b=m.map(Wr(d)),E=b.map(function(g){return r.executeQuerySpec(g,d)});return this.combineResults(E,d.combineWith)},o.prototype.executeQuerySpec=function(e,t){var r,n,a,i,s=$($({},this._options.searchOptions),t),u=(s.fields||this._options.fields).reduce(function(M,z){var y;return $($({},M),(y={},y[z]=Le(s.boost,z)||1,y))},{}),l=s.boostDocument,d=s.weights,h=s.maxFuzzy,v=s.bm25,m=$($({},ft.weights),d),b=m.fuzzy,E=m.prefix,g=this._index.get(e.term),S=this.termResults(e.term,e.term,1,g,u,l,v),T,C;if(e.prefix&&(T=this._index.atPrefix(e.term)),e.fuzzy){var R=e.fuzzy===!0?.2:e.fuzzy,L=R<1?Math.min(h,Math.round(e.term.length*R)):R;L&&(C=this._index.fuzzyGet(e.term,L))}if(T)try{for(var P=D(T),I=P.next();!I.done;I=P.next()){var A=W(I.value,2),_=A[0],O=A[1],x=_.length-e.term.length;if(x){C==null||C.delete(_);var c=E*_.length/(_.length+.3*x);this.termResults(e.term,_,c,O,u,l,v,S)}}}catch(M){r={error:M}}finally{try{I&&!I.done&&(n=P.return)&&n.call(P)}finally{if(r)throw r.error}}if(C)try{for(var f=D(C.keys()),p=f.next();!p.done;p=f.next()){var _=p.value,N=W(C.get(_),2),k=N[0],x=N[1];if(x){var c=b*_.length/(_.length+x);this.termResults(e.term,_,c,k,u,l,v,S)}}}catch(M){a={error:M}}finally{try{p&&!p.done&&(i=f.return)&&i.call(f)}finally{if(a)throw a.error}}return S},o.prototype.executeWildcardQuery=function(e){var t,r,n=new Map,a=$($({},this._options.searchOptions),e);try{for(var i=D(this._documentIds),s=i.next();!s.done;s=i.next()){var u=W(s.value,2),l=u[0],d=u[1],h=a.boostDocument?a.boostDocument(d,"",this._storedFields.get(l)):1;n.set(l,{score:h,terms:[],match:{}})}}catch(v){t={error:v}}finally{try{s&&!s.done&&(r=i.return)&&r.call(i)}finally{if(t)throw t.error}}return n},o.prototype.combineResults=function(e,t){if(t===void 0&&(t=Je),e.length===0)return new Map;var r=t.toLowerCase();return e.reduce(Br[r])||new Map},o.prototype.toJSON=function(){var e,t,r,n,a=[];try{for(var i=D(this._index),s=i.next();!s.done;s=i.next()){var u=W(s.value,2),l=u[0],d=u[1],h={};try{for(var v=(r=void 0,D(d)),m=v.next();!m.done;m=v.next()){var b=W(m.value,2),E=b[0],g=b[1];h[E]=Object.fromEntries(g)}}catch(S){r={error:S}}finally{try{m&&!m.done&&(n=v.return)&&n.call(v)}finally{if(r)throw r.error}}a.push([l,h])}}catch(S){e={error:S}}finally{try{s&&!s.done&&(t=i.return)&&t.call(i)}finally{if(e)throw e.error}}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:a,serializationVersion:2}},o.prototype.termResults=function(e,t,r,n,a,i,s,u){var l,d,h,v,m;if(u===void 0&&(u=new Map),n==null)return u;try{for(var b=D(Object.keys(a)),E=b.next();!E.done;E=b.next()){var g=E.value,S=a[g],T=this._fieldIds[g],C=n.get(T);if(C!=null){var R=C.size,L=this._avgFieldLength[T];try{for(var P=(h=void 0,D(C.keys())),I=P.next();!I.done;I=P.next()){var A=I.value;if(!this._documentIds.has(A)){this.removeTerm(T,A,t),R-=1;continue}var _=i?i(this._documentIds.get(A),t,this._storedFields.get(A)):1;if(_){var O=C.get(A),x=this._fieldLength.get(A)[T],c=$r(O,R,this._documentCount,x,L,s),f=r*S*_*c,p=u.get(A);if(p){p.score+=f,jr(p.terms,e);var N=Le(p.match,t);N?N.push(g):p.match[t]=[g]}else u.set(A,{score:f,terms:[e],match:(m={},m[t]=[g],m)})}}}catch(k){h={error:k}}finally{try{I&&!I.done&&(v=P.return)&&v.call(P)}finally{if(h)throw h.error}}}}}catch(k){l={error:k}}finally{try{E&&!E.done&&(d=b.return)&&d.call(b)}finally{if(l)throw l.error}}return u},o.prototype.addTerm=function(e,t,r){var n=this._index.fetch(r,vt),a=n.get(e);if(a==null)a=new Map,a.set(t,1),n.set(e,a);else{var i=a.get(t);a.set(t,(i||0)+1)}},o.prototype.removeTerm=function(e,t,r){if(!this._index.has(r)){this.warnDocumentChanged(t,e,r);return}var n=this._index.fetch(r,vt),a=n.get(e);a==null||a.get(t)==null?this.warnDocumentChanged(t,e,r):a.get(t)<=1?a.size<=1?n.delete(e):a.delete(t):a.set(t,a.get(t)-1),this._index.get(r).size===0&&this._index.delete(r)},o.prototype.warnDocumentChanged=function(e,t,r){var n,a;try{for(var i=D(Object.keys(this._fieldIds)),s=i.next();!s.done;s=i.next()){var u=s.value;if(this._fieldIds[u]===t){this._options.logger("warn","MiniSearch: document with ID ".concat(this._documentIds.get(e),' has changed before removal: term "').concat(r,'" was not present in field "').concat(u,'". Removing a document after it has changed can corrupt the index!'),"version_conflict");return}}}catch(l){n={error:l}}finally{try{s&&!s.done&&(a=i.return)&&a.call(i)}finally{if(n)throw n.error}}},o.prototype.addDocumentId=function(e){var t=this._nextId;return this._idToShortId.set(e,t),this._documentIds.set(t,e),this._documentCount+=1,this._nextId+=1,t},o.prototype.addFields=function(e){for(var t=0;t(Gt("data-v-6d2f2a19"),o=o(),Qt(),o),Ur=["aria-owns"],Hr={class:"shell"},Gr=["title"],Qr=Y(()=>F("svg",{class:"search-icon",width:"18",height:"18",viewBox:"0 0 24 24","aria-hidden":"true"},[F("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[F("circle",{cx:"11",cy:"11",r:"8"}),F("path",{d:"m21 21l-4.35-4.35"})])],-1)),qr=[Qr],Yr={class:"search-actions before"},Zr=["title"],Xr=Y(()=>F("svg",{width:"18",height:"18",viewBox:"0 0 24 24","aria-hidden":"true"},[F("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M19 12H5m7 7l-7-7l7-7"})],-1)),ea=[Xr],ta=["placeholder"],ra={class:"search-actions"},aa=["title"],na=Y(()=>F("svg",{width:"18",height:"18",viewBox:"0 0 24 24","aria-hidden":"true"},[F("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M3 14h7v7H3zM3 3h7v7H3zm11 1h7m-7 5h7m-7 6h7m-7 5h7"})],-1)),ia=[na],oa=["disabled","title"],sa=Y(()=>F("svg",{width:"18",height:"18",viewBox:"0 0 24 24","aria-hidden":"true"},[F("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M20 5H9l-7 7l7 7h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2Zm-2 4l-6 6m0-6l6 6"})],-1)),ua=[sa],la=["id","role","aria-labelledby"],ca=["aria-selected"],fa=["href","aria-label","onMouseenter","onFocusin"],da={class:"titles"},ha=Y(()=>F("span",{class:"title-icon"},"#",-1)),va=["innerHTML"],pa=Y(()=>F("svg",{width:"18",height:"18",viewBox:"0 0 24 24"},[F("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"m9 18l6-6l-6-6"})],-1)),ya={class:"title main"},ma=["innerHTML"],ga={key:0,class:"excerpt-wrapper"},ba={key:0,class:"excerpt",inert:""},wa=["innerHTML"],xa=Y(()=>F("div",{class:"excerpt-gradient-bottom"},null,-1)),Fa=Y(()=>F("div",{class:"excerpt-gradient-top"},null,-1)),Ea={key:0,class:"no-results"},Sa={class:"search-keyboard-shortcuts"},Aa=["aria-label"],Ca=Y(()=>F("svg",{width:"14",height:"14",viewBox:"0 0 24 24"},[F("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 19V5m-7 7l7-7l7 7"})],-1)),Ta=[Ca],ka=["aria-label"],Na=Y(()=>F("svg",{width:"14",height:"14",viewBox:"0 0 24 24"},[F("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 5v14m7-7l-7 7l-7-7"})],-1)),Ia=[Na],Da=["aria-label"],_a=Y(()=>F("svg",{width:"14",height:"14",viewBox:"0 0 24 24"},[F("g",{fill:"none",stroke:"currentcolor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[F("path",{d:"m9 10l-5 5l5 5"}),F("path",{d:"M20 4v7a4 4 0 0 1-4 4H4"})])],-1)),Oa=[_a],Ra=["aria-label"],Ma=It({__name:"VPLocalSearchBox",emits:["close"],setup(o,{emit:e}){var M,z;const t=e,r=be(),n=be(),a=be(rr),i=er(),{activate:s}=Nr(r,{immediate:!0,allowOutsideClick:!0,clickOutsideDeactivates:!0,escapeDeactivates:!0}),{localeIndex:u,theme:l}=i,d=et(async()=>{var y,w,B,G,K,j,V,J,Q;return nt(zr.loadJSON((B=await((w=(y=a.value)[u.value])==null?void 0:w.call(y)))==null?void 0:B.default,{fields:["title","titles","text"],storeFields:["title","titles"],searchOptions:{fuzzy:.2,prefix:!0,boost:{title:4,text:2,titles:1},...((G=l.value.search)==null?void 0:G.provider)==="local"&&((j=(K=l.value.search.options)==null?void 0:K.miniSearch)==null?void 0:j.searchOptions)},...((V=l.value.search)==null?void 0:V.provider)==="local"&&((Q=(J=l.value.search.options)==null?void 0:J.miniSearch)==null?void 0:Q.options)}))}),v=we(()=>{var y,w;return((y=l.value.search)==null?void 0:y.provider)==="local"&&((w=l.value.search.options)==null?void 0:w.disableQueryPersistence)===!0}).value?ie(""):Dt("vitepress:local-search-filter",""),m=_t("vitepress:local-search-detailed-list",((M=l.value.search)==null?void 0:M.provider)==="local"&&((z=l.value.search.options)==null?void 0:z.detailedView)===!0),b=we(()=>{var y,w,B;return((y=l.value.search)==null?void 0:y.provider)==="local"&&(((w=l.value.search.options)==null?void 0:w.disableDetailedView)===!0||((B=l.value.search.options)==null?void 0:B.detailedView)===!1)}),E=we(()=>{var w,B,G,K,j,V,J;const y=((w=l.value.search)==null?void 0:w.options)??l.value.algolia;return((j=(K=(G=(B=y==null?void 0:y.locales)==null?void 0:B[u.value])==null?void 0:G.translations)==null?void 0:K.button)==null?void 0:j.buttonText)||((J=(V=y==null?void 0:y.translations)==null?void 0:V.button)==null?void 0:J.buttonText)||"Search"});Ot(()=>{b.value&&(m.value=!1)});const g=be([]),S=ie(!1);Be(v,()=>{S.value=!1});const T=et(async()=>{if(n.value)return nt(new Dr(n.value))},null);Rt(()=>[d.value,v.value,m.value],async([y,w,B],G,K)=>{var Ue,He,Ge,Qe;let j=!1;if(K(()=>{j=!0}),!y)return;g.value=y.search(w).slice(0,16),S.value=!0;const V=B?await Promise.all(g.value.map(q=>C(q.id))):[];if(j)return;const J=new Map;for(const{id:q,mod:re}of V){const ae=q.slice(0,q.indexOf("#"));let ee=J.get(ae);if(ee)continue;ee=new Map,J.set(ae,ee);const Z=re.default??re;if(Z!=null&&Z.render||Z!=null&&Z.setup){const ne=qt(Z);ne.config.warnHandler=()=>{},ne.provide(Yt,i),Object.defineProperties(ne.config.globalProperties,{$frontmatter:{get(){return i.frontmatter.value}},$params:{get(){return i.page.value.params}}});const qe=document.createElement("div");ne.mount(qe),qe.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach(fe=>{var Xe;const ge=(Xe=fe.querySelector("a"))==null?void 0:Xe.getAttribute("href"),Ye=(ge==null?void 0:ge.startsWith("#"))&&ge.slice(1);if(!Ye)return;let Ze="";for(;(fe=fe.nextElementSibling)&&!/^h[1-6]$/i.test(fe.tagName);)Ze+=fe.outerHTML;ee.set(Ye,Ze)}),ne.unmount()}if(j)return}const Q=new Set;if(g.value=g.value.map(q=>{const[re,ae]=q.id.split("#"),ee=J.get(re),Z=(ee==null?void 0:ee.get(ae))??"";for(const ne in q.match)Q.add(ne);return{...q,text:Z}}),await de(),j)return;await new Promise(q=>{var re;(re=T.value)==null||re.unmark({done:()=>{var ae;(ae=T.value)==null||ae.markRegExp(k(Q),{done:q})}})});const Ie=((Ue=r.value)==null?void 0:Ue.querySelectorAll(".result .excerpt"))??[];for(const q of Ie)(He=q.querySelector('mark[data-markjs="true"]'))==null||He.scrollIntoView({block:"center"});(Qe=(Ge=n.value)==null?void 0:Ge.firstElementChild)==null||Qe.scrollIntoView({block:"start"})},{debounce:200,immediate:!0});async function C(y){const w=Zt(y.slice(0,y.indexOf("#")));try{if(!w)throw new Error(`Cannot find file for id: ${y}`);return{id:y,mod:await pt(()=>import(w),[])}}catch(B){return console.error(B),{id:y,mod:{}}}}const R=ie(),L=we(()=>{var y;return((y=v.value)==null?void 0:y.length)<=0});function P(y=!0){var w,B;(w=R.value)==null||w.focus(),y&&((B=R.value)==null||B.select())}De(()=>{P()});function I(y){y.pointerType==="mouse"&&P()}const A=ie(-1),_=ie(!1);Be(g,y=>{A.value=y.length?0:-1,O()});function O(){de(()=>{const y=document.querySelector(".result.selected");y&&y.scrollIntoView({block:"nearest"})})}xe("ArrowUp",y=>{y.preventDefault(),A.value--,A.value<0&&(A.value=g.value.length-1),_.value=!0,O()}),xe("ArrowDown",y=>{y.preventDefault(),A.value++,A.value>=g.value.length&&(A.value=0),_.value=!0,O()});const x=Mt();xe("Enter",y=>{if(y.target instanceof HTMLButtonElement&&y.target.type!=="submit")return;const w=g.value[A.value];if(y.target instanceof HTMLInputElement&&!w){y.preventDefault();return}w&&(x.go(w.id),t("close"))}),xe("Escape",()=>{t("close")});const c={modal:{displayDetails:"Display detailed list",resetButtonTitle:"Reset search",backButtonTitle:"Close search",noResultsText:"No results for",footer:{selectText:"to select",selectKeyAriaLabel:"enter",navigateText:"to navigate",navigateUpKeyAriaLabel:"up arrow",navigateDownKeyAriaLabel:"down arrow",closeText:"to close",closeKeyAriaLabel:"escape"}}},f=Lt(tr)(Pt(()=>{var y;return(y=l.value.search)==null?void 0:y.options}),c);De(()=>{window.history.pushState(null,"",null)}),zt("popstate",y=>{y.preventDefault(),t("close")});const p=Bt(Vt?document.body:null);De(()=>{de(()=>{p.value=!0,de().then(()=>s())})}),$t(()=>{p.value=!1});function N(){v.value="",de().then(()=>P(!1))}function k(y){return new RegExp([...y].sort((w,B)=>B.length-w.length).map(w=>`(${w.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d")})`).join("|"),"gi")}return(y,w)=>{var B,G,K,j;return X(),Wt(Ht,{to:"body"},[F("div",{ref_key:"el",ref:r,role:"button","aria-owns":(B=g.value)!=null&&B.length?"localsearch-list":void 0,"aria-expanded":"true","aria-haspopup":"listbox","aria-labelledby":"localsearch-label",class:"VPLocalSearchBox"},[F("div",{class:"backdrop",onClick:w[0]||(w[0]=V=>y.$emit("close"))}),F("div",Hr,[F("form",{class:"search-bar",onPointerup:w[4]||(w[4]=V=>I(V)),onSubmit:w[5]||(w[5]=Kt(()=>{},["prevent"]))},[F("label",{title:E.value,id:"localsearch-label",for:"localsearch-input"},qr,8,Gr),F("div",Yr,[F("button",{class:"back-button",title:U(f)("modal.backButtonTitle"),onClick:w[1]||(w[1]=V=>y.$emit("close"))},ea,8,Zr)]),jt(F("input",{ref_key:"searchInput",ref:R,"onUpdate:modelValue":w[2]||(w[2]=V=>Ut(v)?v.value=V:null),placeholder:E.value,id:"localsearch-input","aria-labelledby":"localsearch-label",class:"search-input"},null,8,ta),[[Jt,U(v)]]),F("div",ra,[b.value?Fe("",!0):(X(),te("button",{key:0,class:tt(["toggle-layout-button",{"detailed-list":U(m)}]),type:"button",title:U(f)("modal.displayDetails"),onClick:w[3]||(w[3]=V=>A.value>-1&&(m.value=!U(m)))},ia,10,aa)),F("button",{class:"clear-button",type:"reset",disabled:L.value,title:U(f)("modal.resetButtonTitle"),onClick:N},ua,8,oa)])],32),F("ul",{ref_key:"resultsEl",ref:n,id:(G=g.value)!=null&&G.length?"localsearch-list":void 0,role:(K=g.value)!=null&&K.length?"listbox":void 0,"aria-labelledby":(j=g.value)!=null&&j.length?"localsearch-label":void 0,class:"results",onMousemove:w[7]||(w[7]=V=>_.value=!1)},[(X(!0),te(at,null,rt(g.value,(V,J)=>(X(),te("li",{key:V.id,role:"option","aria-selected":A.value===J?"true":"false"},[F("a",{href:V.id,class:tt(["result",{selected:A.value===J}]),"aria-label":[...V.titles,V.title].join(" > "),onMouseenter:Q=>!_.value&&(A.value=J),onFocusin:Q=>A.value=J,onClick:w[6]||(w[6]=Q=>y.$emit("close"))},[F("div",null,[F("div",da,[ha,(X(!0),te(at,null,rt(V.titles,(Q,Ie)=>(X(),te("span",{key:Ie,class:"title"},[F("span",{class:"text",innerHTML:Q},null,8,va),pa]))),128)),F("span",ya,[F("span",{class:"text",innerHTML:V.title},null,8,ma)])]),U(m)?(X(),te("div",ga,[V.text?(X(),te("div",ba,[F("div",{class:"vp-doc",innerHTML:V.text},null,8,wa)])):Fe("",!0),xa,Fa])):Fe("",!0)])],42,fa)],8,ca))),128)),U(v)&&!g.value.length&&S.value?(X(),te("li",Ea,[he(ve(U(f)("modal.noResultsText"))+' "',1),F("strong",null,ve(U(v)),1),he('" ')])):Fe("",!0)],40,la),F("div",Sa,[F("span",null,[F("kbd",{"aria-label":U(f)("modal.footer.navigateUpKeyAriaLabel")},Ta,8,Aa),F("kbd",{"aria-label":U(f)("modal.footer.navigateDownKeyAriaLabel")},Ia,8,ka),he(" "+ve(U(f)("modal.footer.navigateText")),1)]),F("span",null,[F("kbd",{"aria-label":U(f)("modal.footer.selectKeyAriaLabel")},Oa,8,Da),he(" "+ve(U(f)("modal.footer.selectText")),1)]),F("span",null,[F("kbd",{"aria-label":U(f)("modal.footer.closeKeyAriaLabel")},"esc",8,Ra),he(" "+ve(U(f)("modal.footer.closeText")),1)])])])],8,Ur)])}}});const Va=Xt(Ma,[["__scopeId","data-v-6d2f2a19"]]);export{Va as default}; diff --git a/assets/chunks/framework.c53372a0.js b/assets/chunks/framework.c53372a0.js new file mode 100644 index 00000000..5052a975 --- /dev/null +++ b/assets/chunks/framework.c53372a0.js @@ -0,0 +1,2 @@ +function Tr(e,t){const n=Object.create(null),r=e.split(",");for(let s=0;s!!n[s.toLowerCase()]:s=>!!n[s]}const te={},yt=[],Oe=()=>{},Ao=()=>!1,Ro=/^on[^a-z]/,en=e=>Ro.test(e),Ar=e=>e.startsWith("onUpdate:"),fe=Object.assign,Rr=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},So=Object.prototype.hasOwnProperty,X=(e,t)=>So.call(e,t),D=Array.isArray,_t=e=>tn(e)==="[object Map]",Nn=e=>tn(e)==="[object Set]",cs=e=>tn(e)==="[object Date]",V=e=>typeof e=="function",ie=e=>typeof e=="string",Tt=e=>typeof e=="symbol",G=e=>e!==null&&typeof e=="object",Sr=e=>(G(e)||V(e))&&V(e.then)&&V(e.catch),oi=Object.prototype.toString,tn=e=>oi.call(e),Oo=e=>tn(e).slice(8,-1),li=e=>tn(e)==="[object Object]",Or=e=>ie(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,kt=Tr(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Bn=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Fo=/-(\w)/g,Be=Bn(e=>e.replace(Fo,(t,n)=>n?n.toUpperCase():"")),Io=/\B([A-Z])/g,ht=Bn(e=>e.replace(Io,"-$1").toLowerCase()),Hn=Bn(e=>e.charAt(0).toUpperCase()+e.slice(1)),vn=Bn(e=>e?`on${Hn(e)}`:""),dt=(e,t)=>!Object.is(e,t),wn=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Tn=e=>{const t=parseFloat(e);return isNaN(t)?e:t},ci=e=>{const t=ie(e)?Number(e):NaN;return isNaN(t)?e:t};let as;const cr=()=>as||(as=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Fr(e){if(D(e)){const t={};for(let n=0;n{if(n){const r=n.split(Mo);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function Ir(e){let t="";if(ie(e))t=e;else if(D(e))for(let n=0;n$n(n,t))}const Za=e=>ie(e)?e:e==null?"":D(e)||G(e)&&(e.toString===oi||!V(e.toString))?JSON.stringify(e,ui,2):String(e),ui=(e,t)=>t&&t.__v_isRef?ui(e,t.value):_t(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,s])=>(n[`${r} =>`]=s,n),{})}:Nn(t)?{[`Set(${t.size})`]:[...t.values()]}:G(t)&&!D(t)&&!li(t)?String(t):t;let ve;class Do{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=ve,!t&&ve&&(this.index=(ve.scopes||(ve.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=ve;try{return ve=this,t()}finally{ve=n}}}on(){ve=this}off(){ve=this.parent}stop(t){if(this._active){let n,r;for(n=0,r=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},di=e=>(e.w&Ge)>0,hi=e=>(e.n&Ge)>0,Ko=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let r=0;r{(f==="length"||!Tt(f)&&f>=c)&&l.push(a)})}else switch(n!==void 0&&l.push(o.get(n)),t){case"add":D(e)?Or(n)&&l.push(o.get("length")):(l.push(o.get(ut)),_t(e)&&l.push(o.get(ur)));break;case"delete":D(e)||(l.push(o.get(ut)),_t(e)&&l.push(o.get(ur)));break;case"set":_t(e)&&l.push(o.get(ut));break}if(l.length===1)l[0]&&fr(l[0]);else{const c=[];for(const a of l)a&&c.push(...a);fr(Pr(c))}}function fr(e,t){const n=D(e)?e:[...e];for(const r of n)r.computed&&fs(r);for(const r of n)r.computed||fs(r)}function fs(e,t){(e!==Se||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function Vo(e,t){var n;return(n=An.get(e))==null?void 0:n.get(t)}const qo=Tr("__proto__,__v_isRef,__isVue"),mi=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Tt)),ds=zo();function zo(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=Q(this);for(let i=0,o=this.length;i{e[t]=function(...n){Ft();const r=Q(this)[t].apply(this,n);return It(),r}}),e}function Yo(e){const t=Q(this);return _e(t,"has",e),t.hasOwnProperty(e)}class yi{constructor(t=!1,n=!1){this._isReadonly=t,this._shallow=n}get(t,n,r){const s=this._isReadonly,i=this._shallow;if(n==="__v_isReactive")return!s;if(n==="__v_isReadonly")return s;if(n==="__v_isShallow")return i;if(n==="__v_raw"&&r===(s?i?ll:wi:i?vi:bi).get(t))return t;const o=D(t);if(!s){if(o&&X(ds,n))return Reflect.get(ds,n,r);if(n==="hasOwnProperty")return Yo}const l=Reflect.get(t,n,r);return(Tt(n)?mi.has(n):qo(n))||(s||_e(t,"get",n),i)?l:ae(l)?o&&Or(n)?l:l.value:G(l)?s?jn(l):Dn(l):l}}class _i extends yi{constructor(t=!1){super(!1,t)}set(t,n,r,s){let i=t[n];if(At(i)&&ae(i)&&!ae(r))return!1;if(!this._shallow&&(!Rn(r)&&!At(r)&&(i=Q(i),r=Q(r)),!D(t)&&ae(i)&&!ae(r)))return i.value=r,!0;const o=D(t)&&Or(n)?Number(n)e,kn=e=>Reflect.getPrototypeOf(e);function ln(e,t,n=!1,r=!1){e=e.__v_raw;const s=Q(e),i=Q(t);n||(dt(t,i)&&_e(s,"get",t),_e(s,"get",i));const{has:o}=kn(s),l=r?Lr:n?Hr:qt;if(o.call(s,t))return l(e.get(t));if(o.call(s,i))return l(e.get(i));e!==s&&e.get(t)}function cn(e,t=!1){const n=this.__v_raw,r=Q(n),s=Q(e);return t||(dt(e,s)&&_e(r,"has",e),_e(r,"has",s)),e===s?n.has(e):n.has(e)||n.has(s)}function an(e,t=!1){return e=e.__v_raw,!t&&_e(Q(e),"iterate",ut),Reflect.get(e,"size",e)}function hs(e){e=Q(e);const t=Q(this);return kn(t).has.call(t,e)||(t.add(e),De(t,"add",e,e)),this}function ps(e,t){t=Q(t);const n=Q(this),{has:r,get:s}=kn(n);let i=r.call(n,e);i||(e=Q(e),i=r.call(n,e));const o=s.call(n,e);return n.set(e,t),i?dt(t,o)&&De(n,"set",e,t):De(n,"add",e,t),this}function gs(e){const t=Q(this),{has:n,get:r}=kn(t);let s=n.call(t,e);s||(e=Q(e),s=n.call(t,e)),r&&r.call(t,e);const i=t.delete(e);return s&&De(t,"delete",e,void 0),i}function ms(){const e=Q(this),t=e.size!==0,n=e.clear();return t&&De(e,"clear",void 0,void 0),n}function un(e,t){return function(r,s){const i=this,o=i.__v_raw,l=Q(o),c=t?Lr:e?Hr:qt;return!e&&_e(l,"iterate",ut),o.forEach((a,f)=>r.call(s,c(a),c(f),i))}}function fn(e,t,n){return function(...r){const s=this.__v_raw,i=Q(s),o=_t(i),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,a=s[e](...r),f=n?Lr:t?Hr:qt;return!t&&_e(i,"iterate",c?ur:ut),{next(){const{value:d,done:g}=a.next();return g?{value:d,done:g}:{value:l?[f(d[0]),f(d[1])]:f(d),done:g}},[Symbol.iterator](){return this}}}}function Ke(e){return function(...t){return e==="delete"?!1:this}}function Go(){const e={get(i){return ln(this,i)},get size(){return an(this)},has:cn,add:hs,set:ps,delete:gs,clear:ms,forEach:un(!1,!1)},t={get(i){return ln(this,i,!1,!0)},get size(){return an(this)},has:cn,add:hs,set:ps,delete:gs,clear:ms,forEach:un(!1,!0)},n={get(i){return ln(this,i,!0)},get size(){return an(this,!0)},has(i){return cn.call(this,i,!0)},add:Ke("add"),set:Ke("set"),delete:Ke("delete"),clear:Ke("clear"),forEach:un(!0,!1)},r={get(i){return ln(this,i,!0,!0)},get size(){return an(this,!0)},has(i){return cn.call(this,i,!0)},add:Ke("add"),set:Ke("set"),delete:Ke("delete"),clear:Ke("clear"),forEach:un(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(i=>{e[i]=fn(i,!1,!1),n[i]=fn(i,!0,!1),t[i]=fn(i,!1,!0),r[i]=fn(i,!0,!0)}),[e,n,t,r]}const[el,tl,nl,rl]=Go();function Nr(e,t){const n=t?e?rl:nl:e?tl:el;return(r,s,i)=>s==="__v_isReactive"?!e:s==="__v_isReadonly"?e:s==="__v_raw"?r:Reflect.get(X(n,s)&&s in r?n:r,s,i)}const sl={get:Nr(!1,!1)},il={get:Nr(!1,!0)},ol={get:Nr(!0,!1)},bi=new WeakMap,vi=new WeakMap,wi=new WeakMap,ll=new WeakMap;function cl(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function al(e){return e.__v_skip||!Object.isExtensible(e)?0:cl(Oo(e))}function Dn(e){return At(e)?e:Br(e,!1,Xo,sl,bi)}function ul(e){return Br(e,!1,Zo,il,vi)}function jn(e){return Br(e,!0,Qo,ol,wi)}function Br(e,t,n,r,s){if(!G(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const i=s.get(e);if(i)return i;const o=al(e);if(o===0)return e;const l=new Proxy(e,o===2?r:n);return s.set(e,l),l}function bt(e){return At(e)?bt(e.__v_raw):!!(e&&e.__v_isReactive)}function At(e){return!!(e&&e.__v_isReadonly)}function Rn(e){return!!(e&&e.__v_isShallow)}function Ci(e){return bt(e)||At(e)}function Q(e){const t=e&&e.__v_raw;return t?Q(t):e}function Dt(e){return xn(e,"__v_skip",!0),e}const qt=e=>G(e)?Dn(e):e,Hr=e=>G(e)?jn(e):e;function $r(e){Je&&Se&&(e=Q(e),gi(e.dep||(e.dep=Pr())))}function kr(e,t){e=Q(e);const n=e.dep;n&&fr(n)}function ae(e){return!!(e&&e.__v_isRef===!0)}function ue(e){return Ei(e,!1)}function Dr(e){return Ei(e,!0)}function Ei(e,t){return ae(e)?e:new fl(e,t)}class fl{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:Q(t),this._value=n?t:qt(t)}get value(){return $r(this),this._value}set value(t){const n=this.__v_isShallow||Rn(t)||At(t);t=n?t:Q(t),dt(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:qt(t),kr(this))}}function jr(e){return ae(e)?e.value:e}const dl={get:(e,t,n)=>jr(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const s=e[t];return ae(s)&&!ae(n)?(s.value=n,!0):Reflect.set(e,t,n,r)}};function xi(e){return bt(e)?e:new Proxy(e,dl)}class hl{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:n,set:r}=t(()=>$r(this),()=>kr(this));this._get=n,this._set=r}get value(){return this._get()}set value(t){this._set(t)}}function pl(e){return new hl(e)}class gl{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return Vo(Q(this._object),this._key)}}class ml{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function yl(e,t,n){return ae(e)?e:V(e)?new ml(e):G(e)&&arguments.length>1?_l(e,t,n):ue(e)}function _l(e,t,n){const r=e[t];return ae(r)?r:new gl(e,t,n)}class bl{constructor(t,n,r,s){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new Mr(t,()=>{this._dirty||(this._dirty=!0,kr(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!s,this.__v_isReadonly=r}get value(){const t=Q(this);return $r(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function vl(e,t,n=!1){let r,s;const i=V(e);return i?(r=e,s=Oe):(r=e.get,s=e.set),new bl(r,s,i||!s,n)}function Xe(e,t,n,r){let s;try{s=r?e(...r):e()}catch(i){Pt(i,t,n)}return s}function Ae(e,t,n,r){if(V(e)){const i=Xe(e,t,n,r);return i&&Sr(i)&&i.catch(o=>{Pt(o,t,n)}),i}const s=[];for(let i=0;i>>1,s=he[r],i=Yt(s);iLe&&he.splice(t,1)}function hr(e){D(e)?vt.push(...e):(!ke||!ke.includes(e,e.allowRecurse?ot+1:ot))&&vt.push(e),Ai()}function ys(e,t=zt?Le+1:0){for(;tYt(n)-Yt(r)),ot=0;ote.id==null?1/0:e.id,xl=(e,t)=>{const n=Yt(e)-Yt(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Ri(e){dr=!1,zt=!0,he.sort(xl);const t=Oe;try{for(Le=0;Leie(b)?b.trim():b)),d&&(s=n.map(Tn))}let l,c=r[l=vn(t)]||r[l=vn(Be(t))];!c&&i&&(c=r[l=vn(ht(t))]),c&&Ae(c,e,6,s);const a=r[l+"Once"];if(a){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Ae(a,e,6,s)}}function Si(e,t,n=!1){const r=t.emitsCache,s=r.get(e);if(s!==void 0)return s;const i=e.emits;let o={},l=!1;if(!V(e)){const c=a=>{const f=Si(a,t,!0);f&&(l=!0,fe(o,f))};!n&&t.mixins.length&&t.mixins.forEach(c),e.extends&&c(e.extends),e.mixins&&e.mixins.forEach(c)}return!i&&!l?(G(e)&&r.set(e,null),null):(D(i)?i.forEach(c=>o[c]=null):fe(o,i),G(e)&&r.set(e,o),o)}function Wn(e,t){return!e||!en(t)?!1:(t=t.slice(2).replace(/Once$/,""),X(e,t[0].toLowerCase()+t.slice(1))||X(e,ht(t))||X(e,t))}let de=null,Vn=null;function On(e){const t=de;return de=e,Vn=e&&e.type.__scopeId||null,t}function Ga(e){Vn=e}function eu(){Vn=null}function Al(e,t=de,n){if(!t||e._n)return e;const r=(...s)=>{r._d&&Is(-1);const i=On(t);let o;try{o=e(...s)}finally{On(i),r._d&&Is(1)}return o};return r._n=!0,r._c=!0,r._d=!0,r}function Gn(e){const{type:t,vnode:n,proxy:r,withProxy:s,props:i,propsOptions:[o],slots:l,attrs:c,emit:a,render:f,renderCache:d,data:g,setupState:b,ctx:v,inheritAttrs:x}=e;let N,k;const H=On(e);try{if(n.shapeFlag&4){const p=s||r;N=Ee(f.call(p,p,d,i,b,g,v)),k=c}else{const p=t;N=Ee(p.length>1?p(i,{attrs:c,slots:l,emit:a}):p(i,null)),k=t.props?c:Sl(c)}}catch(p){Wt.length=0,Pt(p,e,1),N=se(ge)}let y=N;if(k&&x!==!1){const p=Object.keys(k),{shapeFlag:T}=y;p.length&&T&7&&(o&&p.some(Ar)&&(k=Ol(k,o)),y=et(y,k))}return n.dirs&&(y=et(y),y.dirs=y.dirs?y.dirs.concat(n.dirs):n.dirs),n.transition&&(y.transition=n.transition),N=y,On(H),N}function Rl(e){let t;for(let n=0;n{let t;for(const n in e)(n==="class"||n==="style"||en(n))&&((t||(t={}))[n]=e[n]);return t},Ol=(e,t)=>{const n={};for(const r in e)(!Ar(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function Fl(e,t,n){const{props:r,children:s,component:i}=e,{props:o,children:l,patchFlag:c}=t,a=i.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return r?_s(r,o,a):!!o;if(c&8){const f=t.dynamicProps;for(let d=0;de.__isSuspense,Pl={name:"Suspense",__isSuspense:!0,process(e,t,n,r,s,i,o,l,c,a){e==null?Ml(t,n,r,s,i,o,l,c,a):Ll(e,t,n,r,s,o,l,c,a)},hydrate:Nl,create:Vr,normalize:Bl},ru=Pl;function Jt(e,t){const n=e.props&&e.props[t];V(n)&&n()}function Ml(e,t,n,r,s,i,o,l,c){const{p:a,o:{createElement:f}}=c,d=f("div"),g=e.suspense=Vr(e,s,r,t,d,n,i,o,l,c);a(null,g.pendingBranch=e.ssContent,d,null,r,g,i,o),g.deps>0?(Jt(e,"onPending"),Jt(e,"onFallback"),a(null,e.ssFallback,t,n,r,null,i,o),wt(g,e.ssFallback)):g.resolve(!1,!0)}function Ll(e,t,n,r,s,i,o,l,{p:c,um:a,o:{createElement:f}}){const d=t.suspense=e.suspense;d.vnode=t,t.el=e.el;const g=t.ssContent,b=t.ssFallback,{activeBranch:v,pendingBranch:x,isInFallback:N,isHydrating:k}=d;if(x)d.pendingBranch=g,Ne(g,x)?(c(x,g,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0?d.resolve():N&&(c(v,b,n,r,s,null,i,o,l),wt(d,b))):(d.pendingId++,k?(d.isHydrating=!1,d.activeBranch=x):a(x,s,d),d.deps=0,d.effects.length=0,d.hiddenContainer=f("div"),N?(c(null,g,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0?d.resolve():(c(v,b,n,r,s,null,i,o,l),wt(d,b))):v&&Ne(g,v)?(c(v,g,n,r,s,d,i,o,l),d.resolve(!0)):(c(null,g,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0&&d.resolve()));else if(v&&Ne(g,v))c(v,g,n,r,s,d,i,o,l),wt(d,g);else if(Jt(t,"onPending"),d.pendingBranch=g,d.pendingId++,c(null,g,d.hiddenContainer,null,s,d,i,o,l),d.deps<=0)d.resolve();else{const{timeout:H,pendingId:y}=d;H>0?setTimeout(()=>{d.pendingId===y&&d.fallback(b)},H):H===0&&d.fallback(b)}}function Vr(e,t,n,r,s,i,o,l,c,a,f=!1){const{p:d,m:g,um:b,n:v,o:{parentNode:x,remove:N}}=a;let k;const H=Hl(e);H&&t!=null&&t.pendingBranch&&(k=t.pendingId,t.deps++);const y=e.props?ci(e.props.timeout):void 0,p={vnode:e,parent:t,parentComponent:n,isSVG:o,container:r,hiddenContainer:s,anchor:i,deps:0,pendingId:0,timeout:typeof y=="number"?y:-1,activeBranch:null,pendingBranch:null,isInFallback:!0,isHydrating:f,isUnmounted:!1,effects:[],resolve(T=!1,B=!1){const{vnode:M,activeBranch:_,pendingBranch:O,pendingId:R,effects:W,parentComponent:I,container:q}=p;let ne=!1;if(p.isHydrating)p.isHydrating=!1;else if(!T){ne=_&&O.transition&&O.transition.mode==="out-in",ne&&(_.transition.afterLeave=()=>{R===p.pendingId&&(g(O,q,Y,0),hr(W))});let{anchor:Y}=p;_&&(Y=v(_),b(_,I,p,!0)),ne||g(O,q,Y,0)}wt(p,O),p.pendingBranch=null,p.isInFallback=!1;let re=p.parent,$=!1;for(;re;){if(re.pendingBranch){re.effects.push(...W),$=!0;break}re=re.parent}!$&&!ne&&hr(W),p.effects=[],H&&t&&t.pendingBranch&&k===t.pendingId&&(t.deps--,t.deps===0&&!B&&t.resolve()),Jt(M,"onResolve")},fallback(T){if(!p.pendingBranch)return;const{vnode:B,activeBranch:M,parentComponent:_,container:O,isSVG:R}=p;Jt(B,"onFallback");const W=v(M),I=()=>{p.isInFallback&&(d(null,T,O,W,_,null,R,l,c),wt(p,T))},q=T.transition&&T.transition.mode==="out-in";q&&(M.transition.afterLeave=I),p.isInFallback=!0,b(M,_,null,!0),q||I()},move(T,B,M){p.activeBranch&&g(p.activeBranch,T,B,M),p.container=T},next(){return p.activeBranch&&v(p.activeBranch)},registerDep(T,B){const M=!!p.pendingBranch;M&&p.deps++;const _=T.vnode.el;T.asyncDep.catch(O=>{Pt(O,T,0)}).then(O=>{if(T.isUnmounted||p.isUnmounted||p.pendingId!==T.suspenseId)return;T.asyncResolved=!0;const{vnode:R}=T;wr(T,O,!1),_&&(R.el=_);const W=!_&&T.subTree.el;B(T,R,x(_||T.subTree.el),_?null:v(T.subTree),p,o,c),W&&N(W),Kr(T,R.el),M&&--p.deps===0&&p.resolve()})},unmount(T,B){p.isUnmounted=!0,p.activeBranch&&b(p.activeBranch,n,T,B),p.pendingBranch&&b(p.pendingBranch,n,T,B)}};return p}function Nl(e,t,n,r,s,i,o,l,c){const a=t.suspense=Vr(t,r,n,e.parentNode,document.createElement("div"),null,s,i,o,l,!0),f=c(e,a.pendingBranch=t.ssContent,n,a,i,o);return a.deps===0&&a.resolve(!1,!0),f}function Bl(e){const{shapeFlag:t,children:n}=e,r=t&32;e.ssContent=vs(r?n.default:n),e.ssFallback=r?vs(n.fallback):se(ge)}function vs(e){let t;if(V(e)){const n=St&&e._c;n&&(e._d=!1,Qr()),e=e(),n&&(e._d=!0,t=Te,Ji())}return D(e)&&(e=Rl(e)),e=Ee(e),t&&!e.dynamicChildren&&(e.dynamicChildren=t.filter(n=>n!==e)),e}function Ii(e,t){t&&t.pendingBranch?D(e)?t.effects.push(...e):t.effects.push(e):hr(e)}function wt(e,t){e.activeBranch=t;const{vnode:n,parentComponent:r}=e,s=n.el=t.el;r&&r.subTree===n&&(r.vnode.el=s,Kr(r,s))}function Hl(e){var t;return((t=e.props)==null?void 0:t.suspensible)!=null&&e.props.suspensible!==!1}function qr(e,t){return qn(e,null,t)}function su(e,t){return qn(e,null,{flush:"post"})}const dn={};function Qe(e,t,n){return qn(e,t,n)}function qn(e,t,{immediate:n,deep:r,flush:s,onTrack:i,onTrigger:o}=te){var l;const c=fi()===((l=ce)==null?void 0:l.scope)?ce:null;let a,f=!1,d=!1;if(ae(e)?(a=()=>e.value,f=Rn(e)):bt(e)?(a=()=>e,r=!0):D(e)?(d=!0,f=e.some(p=>bt(p)||Rn(p)),a=()=>e.map(p=>{if(ae(p))return p.value;if(bt(p))return at(p);if(V(p))return Xe(p,c,2)})):V(e)?t?a=()=>Xe(e,c,2):a=()=>{if(!(c&&c.isUnmounted))return g&&g(),Ae(e,c,3,[b])}:a=Oe,t&&r){const p=a;a=()=>at(p())}let g,b=p=>{g=H.onStop=()=>{Xe(p,c,4)}},v;if(Ot)if(b=Oe,t?n&&Ae(t,c,3,[a(),d?[]:void 0,b]):a(),s==="sync"){const p=Pc();v=p.__watcherHandles||(p.__watcherHandles=[])}else return Oe;let x=d?new Array(e.length).fill(dn):dn;const N=()=>{if(H.active)if(t){const p=H.run();(r||f||(d?p.some((T,B)=>dt(T,x[B])):dt(p,x)))&&(g&&g(),Ae(t,c,3,[p,x===dn?void 0:d&&x[0]===dn?[]:x,b]),x=p)}else H.run()};N.allowRecurse=!!t;let k;s==="sync"?k=N:s==="post"?k=()=>me(N,c&&c.suspense):(N.pre=!0,c&&(N.id=c.uid),k=()=>Kn(N));const H=new Mr(a,k);t?n?N():x=H.run():s==="post"?me(H.run.bind(H),c&&c.suspense):H.run();const y=()=>{H.stop(),c&&c.scope&&Rr(c.scope.effects,H)};return v&&v.push(y),y}function $l(e,t,n){const r=this.proxy,s=ie(e)?e.includes(".")?Pi(r,e):()=>r[e]:e.bind(r,r);let i;V(t)?i=t:(i=t.handler,n=t);const o=ce;tt(this);const l=qn(s,i.bind(r),n);return o?tt(o):Ze(),l}function Pi(e,t){const n=t.split(".");return()=>{let r=e;for(let s=0;s{at(n,t)});else if(li(e))for(const n in e)at(e[n],t);return e}function iu(e,t){const n=de;if(n===null)return e;const r=Xn(n)||n.proxy,s=e.dirs||(e.dirs=[]);for(let i=0;i{e.isMounted=!0}),Hi(()=>{e.isUnmounting=!0}),e}const we=[Function,Array],Mi={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:we,onEnter:we,onAfterEnter:we,onEnterCancelled:we,onBeforeLeave:we,onLeave:we,onAfterLeave:we,onLeaveCancelled:we,onBeforeAppear:we,onAppear:we,onAfterAppear:we,onAppearCancelled:we},Dl={name:"BaseTransition",props:Mi,setup(e,{slots:t}){const n=rn(),r=kl();let s;return()=>{const i=t.default&&Ni(t.default(),!0);if(!i||!i.length)return;let o=i[0];if(i.length>1){for(const x of i)if(x.type!==ge){o=x;break}}const l=Q(e),{mode:c}=l;if(r.isLeaving)return er(o);const a=ws(o);if(!a)return er(o);const f=pr(a,l,r,n);gr(a,f);const d=n.subTree,g=d&&ws(d);let b=!1;const{getTransitionKey:v}=a.type;if(v){const x=v();s===void 0?s=x:x!==s&&(s=x,b=!0)}if(g&&g.type!==ge&&(!Ne(a,g)||b)){const x=pr(g,l,r,n);if(gr(g,x),c==="out-in")return r.isLeaving=!0,x.afterLeave=()=>{r.isLeaving=!1,n.update.active!==!1&&n.update()},er(o);c==="in-out"&&a.type!==ge&&(x.delayLeave=(N,k,H)=>{const y=Li(r,g);y[String(g.key)]=g,N[ze]=()=>{k(),N[ze]=void 0,delete f.delayedLeave},f.delayedLeave=H})}return o}}},jl=Dl;function Li(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function pr(e,t,n,r){const{appear:s,mode:i,persisted:o=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:a,onEnterCancelled:f,onBeforeLeave:d,onLeave:g,onAfterLeave:b,onLeaveCancelled:v,onBeforeAppear:x,onAppear:N,onAfterAppear:k,onAppearCancelled:H}=t,y=String(e.key),p=Li(n,e),T=(_,O)=>{_&&Ae(_,r,9,O)},B=(_,O)=>{const R=O[1];T(_,O),D(_)?_.every(W=>W.length<=1)&&R():_.length<=1&&R()},M={mode:i,persisted:o,beforeEnter(_){let O=l;if(!n.isMounted)if(s)O=x||l;else return;_[ze]&&_[ze](!0);const R=p[y];R&&Ne(e,R)&&R.el[ze]&&R.el[ze](),T(O,[_])},enter(_){let O=c,R=a,W=f;if(!n.isMounted)if(s)O=N||c,R=k||a,W=H||f;else return;let I=!1;const q=_[hn]=ne=>{I||(I=!0,ne?T(W,[_]):T(R,[_]),M.delayedLeave&&M.delayedLeave(),_[hn]=void 0)};O?B(O,[_,q]):q()},leave(_,O){const R=String(e.key);if(_[hn]&&_[hn](!0),n.isUnmounting)return O();T(d,[_]);let W=!1;const I=_[ze]=q=>{W||(W=!0,O(),q?T(v,[_]):T(b,[_]),_[ze]=void 0,p[R]===e&&delete p[R])};p[R]=e,g?B(g,[_,I]):I()},clone(_){return pr(_,t,n,r)}};return M}function er(e){if(nn(e))return e=et(e),e.children=null,e}function ws(e){return nn(e)?e.children?e.children[0]:void 0:e}function gr(e,t){e.shapeFlag&6&&e.component?gr(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Ni(e,t=!1,n){let r=[],s=0;for(let i=0;i1)for(let i=0;ife({name:e.name},t,{setup:e}))():e}const Ct=e=>!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function ou(e){V(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:s=200,timeout:i,suspensible:o=!0,onError:l}=e;let c=null,a,f=0;const d=()=>(f++,c=null,g()),g=()=>{let b;return c||(b=c=t().catch(v=>{if(v=v instanceof Error?v:new Error(String(v)),l)return new Promise((x,N)=>{l(v,()=>x(d()),()=>N(v),f+1)});throw v}).then(v=>b!==c&&c?c:(v&&(v.__esModule||v[Symbol.toStringTag]==="Module")&&(v=v.default),a=v,v)))};return zr({name:"AsyncComponentWrapper",__asyncLoader:g,get __asyncResolved(){return a},setup(){const b=ce;if(a)return()=>tr(a,b);const v=H=>{c=null,Pt(H,b,13,!r)};if(o&&b.suspense||Ot)return g().then(H=>()=>tr(H,b)).catch(H=>(v(H),()=>r?se(r,{error:H}):null));const x=ue(!1),N=ue(),k=ue(!!s);return s&&setTimeout(()=>{k.value=!1},s),i!=null&&setTimeout(()=>{if(!x.value&&!N.value){const H=new Error(`Async component timed out after ${i}ms.`);v(H),N.value=H}},i),g().then(()=>{x.value=!0,b.parent&&nn(b.parent.vnode)&&Kn(b.parent.update)}).catch(H=>{v(H),N.value=H}),()=>{if(x.value&&a)return tr(a,b);if(N.value&&r)return se(r,{error:N.value});if(n&&!k.value)return se(n)}}})}function tr(e,t){const{ref:n,props:r,children:s,ce:i}=t.vnode,o=se(e,r,s);return o.ref=n,o.ce=i,delete t.vnode.ce,o}const nn=e=>e.type.__isKeepAlive;function Ul(e,t){Bi(e,"a",t)}function Kl(e,t){Bi(e,"da",t)}function Bi(e,t,n=ce){const r=e.__wdc||(e.__wdc=()=>{let s=n;for(;s;){if(s.isDeactivated)return;s=s.parent}return e()});if(zn(t,r,n),n){let s=n.parent;for(;s&&s.parent;)nn(s.parent.vnode)&&Wl(r,t,n,s),s=s.parent}}function Wl(e,t,n,r){const s=zn(t,e,r,!0);Yn(()=>{Rr(r[t],s)},n)}function zn(e,t,n=ce,r=!1){if(n){const s=n[e]||(n[e]=[]),i=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;Ft(),tt(n);const l=Ae(t,n,e,o);return Ze(),It(),l});return r?s.unshift(i):s.push(i),i}}const Ue=e=>(t,n=ce)=>(!Ot||e==="sp")&&zn(e,(...r)=>t(...r),n),Vl=Ue("bm"),Mt=Ue("m"),ql=Ue("bu"),zl=Ue("u"),Hi=Ue("bum"),Yn=Ue("um"),Yl=Ue("sp"),Jl=Ue("rtg"),Xl=Ue("rtc");function Ql(e,t=ce){zn("ec",e,t)}function lu(e,t,n,r){let s;const i=n&&n[r];if(D(e)||ie(e)){s=new Array(e.length);for(let o=0,l=e.length;ot(o,l,void 0,i&&i[l]));else{const o=Object.keys(e);s=new Array(o.length);for(let l=0,c=o.length;lXt(t)?!(t.type===ge||t.type===ye&&!$i(t.children)):!0)?e:null}function au(e,t){const n={};for(const r in e)n[t&&/[A-Z]/.test(r)?`on:${r}`:vn(r)]=e[r];return n}const mr=e=>e?to(e)?Xn(e)||e.proxy:mr(e.parent):null,jt=fe(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>mr(e.parent),$root:e=>mr(e.root),$emit:e=>e.emit,$options:e=>Yr(e),$forceUpdate:e=>e.f||(e.f=()=>Kn(e.update)),$nextTick:e=>e.n||(e.n=Un.bind(e.proxy)),$watch:e=>$l.bind(e)}),nr=(e,t)=>e!==te&&!e.__isScriptSetup&&X(e,t),Zl={get({_:e},t){const{ctx:n,setupState:r,data:s,props:i,accessCache:o,type:l,appContext:c}=e;let a;if(t[0]!=="$"){const b=o[t];if(b!==void 0)switch(b){case 1:return r[t];case 2:return s[t];case 4:return n[t];case 3:return i[t]}else{if(nr(r,t))return o[t]=1,r[t];if(s!==te&&X(s,t))return o[t]=2,s[t];if((a=e.propsOptions[0])&&X(a,t))return o[t]=3,i[t];if(n!==te&&X(n,t))return o[t]=4,n[t];yr&&(o[t]=0)}}const f=jt[t];let d,g;if(f)return t==="$attrs"&&_e(e,"get",t),f(e);if((d=l.__cssModules)&&(d=d[t]))return d;if(n!==te&&X(n,t))return o[t]=4,n[t];if(g=c.config.globalProperties,X(g,t))return g[t]},set({_:e},t,n){const{data:r,setupState:s,ctx:i}=e;return nr(s,t)?(s[t]=n,!0):r!==te&&X(r,t)?(r[t]=n,!0):X(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(i[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:s,propsOptions:i}},o){let l;return!!n[o]||e!==te&&X(e,o)||nr(t,o)||(l=i[0])&&X(l,o)||X(r,o)||X(jt,o)||X(s.config.globalProperties,o)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:X(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function uu(){return Gl().slots}function Gl(){const e=rn();return e.setupContext||(e.setupContext=ro(e))}function Cs(e){return D(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}function fu(e){const t=rn();let n=e();return Ze(),Sr(n)&&(n=n.catch(r=>{throw tt(t),r})),[n,()=>tt(t)]}let yr=!0;function ec(e){const t=Yr(e),n=e.proxy,r=e.ctx;yr=!1,t.beforeCreate&&Es(t.beforeCreate,e,"bc");const{data:s,computed:i,methods:o,watch:l,provide:c,inject:a,created:f,beforeMount:d,mounted:g,beforeUpdate:b,updated:v,activated:x,deactivated:N,beforeDestroy:k,beforeUnmount:H,destroyed:y,unmounted:p,render:T,renderTracked:B,renderTriggered:M,errorCaptured:_,serverPrefetch:O,expose:R,inheritAttrs:W,components:I,directives:q,filters:ne}=t;if(a&&tc(a,r,null),o)for(const Y in o){const K=o[Y];V(K)&&(r[Y]=K.bind(n))}if(s){const Y=s.call(n,n);G(Y)&&(e.data=Dn(Y))}if(yr=!0,i)for(const Y in i){const K=i[Y],He=V(K)?K.bind(n,n):V(K.get)?K.get.bind(n,n):Oe,sn=!V(K)&&V(K.set)?K.set.bind(n):Oe,nt=le({get:He,set:sn});Object.defineProperty(r,Y,{enumerable:!0,configurable:!0,get:()=>nt.value,set:Ie=>nt.value=Ie})}if(l)for(const Y in l)ki(l[Y],r,n,Y);if(c){const Y=V(c)?c.call(n):c;Reflect.ownKeys(Y).forEach(K=>{lc(K,Y[K])})}f&&Es(f,e,"c");function $(Y,K){D(K)?K.forEach(He=>Y(He.bind(n))):K&&Y(K.bind(n))}if($(Vl,d),$(Mt,g),$(ql,b),$(zl,v),$(Ul,x),$(Kl,N),$(Ql,_),$(Xl,B),$(Jl,M),$(Hi,H),$(Yn,p),$(Yl,O),D(R))if(R.length){const Y=e.exposed||(e.exposed={});R.forEach(K=>{Object.defineProperty(Y,K,{get:()=>n[K],set:He=>n[K]=He})})}else e.exposed||(e.exposed={});T&&e.render===Oe&&(e.render=T),W!=null&&(e.inheritAttrs=W),I&&(e.components=I),q&&(e.directives=q)}function tc(e,t,n=Oe){D(e)&&(e=_r(e));for(const r in e){const s=e[r];let i;G(s)?"default"in s?i=Et(s.from||r,s.default,!0):i=Et(s.from||r):i=Et(s),ae(i)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>i.value,set:o=>i.value=o}):t[r]=i}}function Es(e,t,n){Ae(D(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function ki(e,t,n,r){const s=r.includes(".")?Pi(n,r):()=>n[r];if(ie(e)){const i=t[e];V(i)&&Qe(s,i)}else if(V(e))Qe(s,e.bind(n));else if(G(e))if(D(e))e.forEach(i=>ki(i,t,n,r));else{const i=V(e.handler)?e.handler.bind(n):t[e.handler];V(i)&&Qe(s,i,e)}}function Yr(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:s,optionsCache:i,config:{optionMergeStrategies:o}}=e.appContext,l=i.get(t);let c;return l?c=l:!s.length&&!n&&!r?c=t:(c={},s.length&&s.forEach(a=>Fn(c,a,o,!0)),Fn(c,t,o)),G(t)&&i.set(t,c),c}function Fn(e,t,n,r=!1){const{mixins:s,extends:i}=t;i&&Fn(e,i,n,!0),s&&s.forEach(o=>Fn(e,o,n,!0));for(const o in t)if(!(r&&o==="expose")){const l=nc[o]||n&&n[o];e[o]=l?l(e[o],t[o]):t[o]}return e}const nc={data:xs,props:Ts,emits:Ts,methods:$t,computed:$t,beforeCreate:pe,created:pe,beforeMount:pe,mounted:pe,beforeUpdate:pe,updated:pe,beforeDestroy:pe,beforeUnmount:pe,destroyed:pe,unmounted:pe,activated:pe,deactivated:pe,errorCaptured:pe,serverPrefetch:pe,components:$t,directives:$t,watch:sc,provide:xs,inject:rc};function xs(e,t){return t?e?function(){return fe(V(e)?e.call(this,this):e,V(t)?t.call(this,this):t)}:t:e}function rc(e,t){return $t(_r(e),_r(t))}function _r(e){if(D(e)){const t={};for(let n=0;n1)return n&&V(t)?t.call(r&&r.proxy):t}}function cc(e,t,n,r=!1){const s={},i={};xn(i,Jn,1),e.propsDefaults=Object.create(null),ji(e,t,s,i);for(const o in e.propsOptions[0])o in s||(s[o]=void 0);n?e.props=r?s:ul(s):e.type.props?e.props=s:e.props=i,e.attrs=i}function ac(e,t,n,r){const{props:s,attrs:i,vnode:{patchFlag:o}}=e,l=Q(s),[c]=e.propsOptions;let a=!1;if((r||o>0)&&!(o&16)){if(o&8){const f=e.vnode.dynamicProps;for(let d=0;d{c=!0;const[g,b]=Ui(d,t,!0);fe(o,g),b&&l.push(...b)};!n&&t.mixins.length&&t.mixins.forEach(f),e.extends&&f(e.extends),e.mixins&&e.mixins.forEach(f)}if(!i&&!c)return G(e)&&r.set(e,yt),yt;if(D(i))for(let f=0;f-1,b[1]=x<0||v-1||X(b,"default"))&&l.push(d)}}}const a=[o,l];return G(e)&&r.set(e,a),a}function As(e){return e[0]!=="$"}function Rs(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function Ss(e,t){return Rs(e)===Rs(t)}function Os(e,t){return D(t)?t.findIndex(n=>Ss(n,e)):V(t)&&Ss(t,e)?0:-1}const Ki=e=>e[0]==="_"||e==="$stable",Jr=e=>D(e)?e.map(Ee):[Ee(e)],uc=(e,t,n)=>{if(t._n)return t;const r=Al((...s)=>Jr(t(...s)),n);return r._c=!1,r},Wi=(e,t,n)=>{const r=e._ctx;for(const s in e){if(Ki(s))continue;const i=e[s];if(V(i))t[s]=uc(s,i,r);else if(i!=null){const o=Jr(i);t[s]=()=>o}}},Vi=(e,t)=>{const n=Jr(t);e.slots.default=()=>n},fc=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=Q(t),xn(t,"_",n)):Wi(t,e.slots={})}else e.slots={},t&&Vi(e,t);xn(e.slots,Jn,1)},dc=(e,t,n)=>{const{vnode:r,slots:s}=e;let i=!0,o=te;if(r.shapeFlag&32){const l=t._;l?n&&l===1?i=!1:(fe(s,t),!n&&l===1&&delete s._):(i=!t.$stable,Wi(t,s)),o=t}else t&&(Vi(e,t),o={default:1});if(i)for(const l in s)!Ki(l)&&o[l]==null&&delete s[l]};function Pn(e,t,n,r,s=!1){if(D(e)){e.forEach((g,b)=>Pn(g,t&&(D(t)?t[b]:t),n,r,s));return}if(Ct(r)&&!s)return;const i=r.shapeFlag&4?Xn(r.component)||r.component.proxy:r.el,o=s?null:i,{i:l,r:c}=e,a=t&&t.r,f=l.refs===te?l.refs={}:l.refs,d=l.setupState;if(a!=null&&a!==c&&(ie(a)?(f[a]=null,X(d,a)&&(d[a]=null)):ae(a)&&(a.value=null)),V(c))Xe(c,l,12,[o,f]);else{const g=ie(c),b=ae(c);if(g||b){const v=()=>{if(e.f){const x=g?X(d,c)?d[c]:f[c]:c.value;s?D(x)&&Rr(x,i):D(x)?x.includes(i)||x.push(i):g?(f[c]=[i],X(d,c)&&(d[c]=f[c])):(c.value=[i],e.k&&(f[e.k]=c.value))}else g?(f[c]=o,X(d,c)&&(d[c]=o)):b&&(c.value=o,e.k&&(f[e.k]=o))};o?(v.id=-1,me(v,n)):v()}}}let We=!1;const pn=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",gn=e=>e.nodeType===8;function hc(e){const{mt:t,p:n,o:{patchProp:r,createText:s,nextSibling:i,parentNode:o,remove:l,insert:c,createComment:a}}=e,f=(y,p)=>{if(!p.hasChildNodes()){n(null,y,p),Sn(),p._vnode=y;return}We=!1,d(p.firstChild,y,null,null,null),Sn(),p._vnode=y,We&&console.error("Hydration completed but contains mismatches.")},d=(y,p,T,B,M,_=!1)=>{const O=gn(y)&&y.data==="[",R=()=>x(y,p,T,B,M,O),{type:W,ref:I,shapeFlag:q,patchFlag:ne}=p;let re=y.nodeType;p.el=y,ne===-2&&(_=!1,p.dynamicChildren=null);let $=null;switch(W){case Rt:re!==3?p.children===""?(c(p.el=s(""),o(y),y),$=y):$=R():(y.data!==p.children&&(We=!0,y.data=p.children),$=i(y));break;case ge:H(y)?($=i(y),k(p.el=y.content.firstChild,y,T)):re!==8||O?$=R():$=i(y);break;case Kt:if(O&&(y=i(y),re=y.nodeType),re===1||re===3){$=y;const Y=!p.children.length;for(let K=0;K{_=_||!!p.dynamicChildren;const{type:O,props:R,patchFlag:W,shapeFlag:I,dirs:q,transition:ne}=p,re=O==="input"&&q||O==="option";if(re||W!==-1){if(q&&Me(p,null,T,"created"),R)if(re||!_||W&48)for(const K in R)(re&&K.endsWith("value")||en(K)&&!kt(K))&&r(y,K,null,R[K],!1,void 0,T);else R.onClick&&r(y,"onClick",null,R.onClick,!1,void 0,T);let $;($=R&&R.onVnodeBeforeMount)&&Ce($,T,p);let Y=!1;if(H(y)){Y=zi(B,ne)&&T&&T.vnode.props&&T.vnode.props.appear;const K=y.content.firstChild;Y&&ne.beforeEnter(K),k(K,y,T),p.el=y=K}if(q&&Me(p,null,T,"beforeMount"),(($=R&&R.onVnodeMounted)||q||Y)&&Ii(()=>{$&&Ce($,T,p),Y&&ne.enter(y),q&&Me(p,null,T,"mounted")},B),I&16&&!(R&&(R.innerHTML||R.textContent))){let K=b(y.firstChild,p,y,T,B,M,_);for(;K;){We=!0;const He=K;K=K.nextSibling,l(He)}}else I&8&&y.textContent!==p.children&&(We=!0,y.textContent=p.children)}return y.nextSibling},b=(y,p,T,B,M,_,O)=>{O=O||!!p.dynamicChildren;const R=p.children,W=R.length;for(let I=0;I{const{slotScopeIds:O}=p;O&&(M=M?M.concat(O):O);const R=o(y),W=b(i(y),p,R,T,B,M,_);return W&&gn(W)&&W.data==="]"?i(p.anchor=W):(We=!0,c(p.anchor=a("]"),R,W),W)},x=(y,p,T,B,M,_)=>{if(We=!0,p.el=null,_){const W=N(y);for(;;){const I=i(y);if(I&&I!==W)l(I);else break}}const O=i(y),R=o(y);return l(y),n(null,p,R,O,T,B,pn(R),M),O},N=(y,p="[",T="]")=>{let B=0;for(;y;)if(y=i(y),y&&gn(y)&&(y.data===p&&B++,y.data===T)){if(B===0)return i(y);B--}return y},k=(y,p,T)=>{const B=p.parentNode;B&&B.replaceChild(y,p);let M=T;for(;M;)M.vnode.el===p&&(M.vnode.el=M.subTree.el=y),M=M.parent},H=y=>y.nodeType===1&&y.tagName.toLowerCase()==="template";return[f,d]}const me=Ii;function pc(e){return qi(e)}function gc(e){return qi(e,hc)}function qi(e,t){const n=cr();n.__VUE__=!0;const{insert:r,remove:s,patchProp:i,createElement:o,createText:l,createComment:c,setText:a,setElementText:f,parentNode:d,nextSibling:g,setScopeId:b=Oe,insertStaticContent:v}=e,x=(u,h,m,w=null,C=null,S=null,P=!1,A=null,F=!!h.dynamicChildren)=>{if(u===h)return;u&&!Ne(u,h)&&(w=on(u),Ie(u,C,S,!0),u=null),h.patchFlag===-2&&(F=!1,h.dynamicChildren=null);const{type:E,ref:j,shapeFlag:L}=h;switch(E){case Rt:N(u,h,m,w);break;case ge:k(u,h,m,w);break;case Kt:u==null&&H(h,m,w,P);break;case ye:I(u,h,m,w,C,S,P,A,F);break;default:L&1?T(u,h,m,w,C,S,P,A,F):L&6?q(u,h,m,w,C,S,P,A,F):(L&64||L&128)&&E.process(u,h,m,w,C,S,P,A,F,pt)}j!=null&&C&&Pn(j,u&&u.ref,S,h||u,!h)},N=(u,h,m,w)=>{if(u==null)r(h.el=l(h.children),m,w);else{const C=h.el=u.el;h.children!==u.children&&a(C,h.children)}},k=(u,h,m,w)=>{u==null?r(h.el=c(h.children||""),m,w):h.el=u.el},H=(u,h,m,w)=>{[u.el,u.anchor]=v(u.children,h,m,w,u.el,u.anchor)},y=({el:u,anchor:h},m,w)=>{let C;for(;u&&u!==h;)C=g(u),r(u,m,w),u=C;r(h,m,w)},p=({el:u,anchor:h})=>{let m;for(;u&&u!==h;)m=g(u),s(u),u=m;s(h)},T=(u,h,m,w,C,S,P,A,F)=>{P=P||h.type==="svg",u==null?B(h,m,w,C,S,P,A,F):O(u,h,C,S,P,A,F)},B=(u,h,m,w,C,S,P,A)=>{let F,E;const{type:j,props:L,shapeFlag:U,transition:z,dirs:J}=u;if(F=u.el=o(u.type,S,L&&L.is,L),U&8?f(F,u.children):U&16&&_(u.children,F,null,w,C,S&&j!=="foreignObject",P,A),J&&Me(u,null,w,"created"),M(F,u,u.scopeId,P,w),L){for(const Z in L)Z!=="value"&&!kt(Z)&&i(F,Z,null,L[Z],S,u.children,w,C,$e);"value"in L&&i(F,"value",null,L.value),(E=L.onVnodeBeforeMount)&&Ce(E,w,u)}J&&Me(u,null,w,"beforeMount");const ee=zi(C,z);ee&&z.beforeEnter(F),r(F,h,m),((E=L&&L.onVnodeMounted)||ee||J)&&me(()=>{E&&Ce(E,w,u),ee&&z.enter(F),J&&Me(u,null,w,"mounted")},C)},M=(u,h,m,w,C)=>{if(m&&b(u,m),w)for(let S=0;S{for(let E=F;E{const A=h.el=u.el;let{patchFlag:F,dynamicChildren:E,dirs:j}=h;F|=u.patchFlag&16;const L=u.props||te,U=h.props||te;let z;m&&rt(m,!1),(z=U.onVnodeBeforeUpdate)&&Ce(z,m,h,u),j&&Me(h,u,m,"beforeUpdate"),m&&rt(m,!0);const J=C&&h.type!=="foreignObject";if(E?R(u.dynamicChildren,E,A,m,w,J,S):P||K(u,h,A,null,m,w,J,S,!1),F>0){if(F&16)W(A,h,L,U,m,w,C);else if(F&2&&L.class!==U.class&&i(A,"class",null,U.class,C),F&4&&i(A,"style",L.style,U.style,C),F&8){const ee=h.dynamicProps;for(let Z=0;Z{z&&Ce(z,m,h,u),j&&Me(h,u,m,"updated")},w)},R=(u,h,m,w,C,S,P)=>{for(let A=0;A{if(m!==w){if(m!==te)for(const A in m)!kt(A)&&!(A in w)&&i(u,A,m[A],null,P,h.children,C,S,$e);for(const A in w){if(kt(A))continue;const F=w[A],E=m[A];F!==E&&A!=="value"&&i(u,A,E,F,P,h.children,C,S,$e)}"value"in w&&i(u,"value",m.value,w.value)}},I=(u,h,m,w,C,S,P,A,F)=>{const E=h.el=u?u.el:l(""),j=h.anchor=u?u.anchor:l("");let{patchFlag:L,dynamicChildren:U,slotScopeIds:z}=h;z&&(A=A?A.concat(z):z),u==null?(r(E,m,w),r(j,m,w),_(h.children,m,j,C,S,P,A,F)):L>0&&L&64&&U&&u.dynamicChildren?(R(u.dynamicChildren,U,m,C,S,P,A),(h.key!=null||C&&h===C.subTree)&&Xr(u,h,!0)):K(u,h,m,j,C,S,P,A,F)},q=(u,h,m,w,C,S,P,A,F)=>{h.slotScopeIds=A,u==null?h.shapeFlag&512?C.ctx.activate(h,m,w,P,F):ne(h,m,w,C,S,P,F):re(u,h,F)},ne=(u,h,m,w,C,S,P)=>{const A=u.component=Tc(u,w,C);if(nn(u)&&(A.ctx.renderer=pt),Ac(A),A.asyncDep){if(C&&C.registerDep(A,$),!u.el){const F=A.subTree=se(ge);k(null,F,h,m)}return}$(A,u,h,m,C,S,P)},re=(u,h,m)=>{const w=h.component=u.component;if(Fl(u,h,m))if(w.asyncDep&&!w.asyncResolved){Y(w,h,m);return}else w.next=h,El(w.update),w.update();else h.el=u.el,w.vnode=h},$=(u,h,m,w,C,S,P)=>{const A=()=>{if(u.isMounted){let{next:j,bu:L,u:U,parent:z,vnode:J}=u,ee=j,Z;rt(u,!1),j?(j.el=J.el,Y(u,j,P)):j=J,L&&wn(L),(Z=j.props&&j.props.onVnodeBeforeUpdate)&&Ce(Z,z,j,J),rt(u,!0);const oe=Gn(u),Re=u.subTree;u.subTree=oe,x(Re,oe,d(Re.el),on(Re),u,C,S),j.el=oe.el,ee===null&&Kr(u,oe.el),U&&me(U,C),(Z=j.props&&j.props.onVnodeUpdated)&&me(()=>Ce(Z,z,j,J),C)}else{let j;const{el:L,props:U}=h,{bm:z,m:J,parent:ee}=u,Z=Ct(h);if(rt(u,!1),z&&wn(z),!Z&&(j=U&&U.onVnodeBeforeMount)&&Ce(j,ee,h),rt(u,!0),L&&Zn){const oe=()=>{u.subTree=Gn(u),Zn(L,u.subTree,u,C,null)};Z?h.type.__asyncLoader().then(()=>!u.isUnmounted&&oe()):oe()}else{const oe=u.subTree=Gn(u);x(null,oe,m,w,u,C,S),h.el=oe.el}if(J&&me(J,C),!Z&&(j=U&&U.onVnodeMounted)){const oe=h;me(()=>Ce(j,ee,oe),C)}(h.shapeFlag&256||ee&&Ct(ee.vnode)&&ee.vnode.shapeFlag&256)&&u.a&&me(u.a,C),u.isMounted=!0,h=m=w=null}},F=u.effect=new Mr(A,()=>Kn(E),u.scope),E=u.update=()=>F.run();E.id=u.uid,rt(u,!0),E()},Y=(u,h,m)=>{h.component=u;const w=u.vnode.props;u.vnode=h,u.next=null,ac(u,h.props,w,m),dc(u,h.children,m),Ft(),ys(),It()},K=(u,h,m,w,C,S,P,A,F=!1)=>{const E=u&&u.children,j=u?u.shapeFlag:0,L=h.children,{patchFlag:U,shapeFlag:z}=h;if(U>0){if(U&128){sn(E,L,m,w,C,S,P,A,F);return}else if(U&256){He(E,L,m,w,C,S,P,A,F);return}}z&8?(j&16&&$e(E,C,S),L!==E&&f(m,L)):j&16?z&16?sn(E,L,m,w,C,S,P,A,F):$e(E,C,S,!0):(j&8&&f(m,""),z&16&&_(L,m,w,C,S,P,A,F))},He=(u,h,m,w,C,S,P,A,F)=>{u=u||yt,h=h||yt;const E=u.length,j=h.length,L=Math.min(E,j);let U;for(U=0;Uj?$e(u,C,S,!0,!1,L):_(h,m,w,C,S,P,A,F,L)},sn=(u,h,m,w,C,S,P,A,F)=>{let E=0;const j=h.length;let L=u.length-1,U=j-1;for(;E<=L&&E<=U;){const z=u[E],J=h[E]=F?Ye(h[E]):Ee(h[E]);if(Ne(z,J))x(z,J,m,null,C,S,P,A,F);else break;E++}for(;E<=L&&E<=U;){const z=u[L],J=h[U]=F?Ye(h[U]):Ee(h[U]);if(Ne(z,J))x(z,J,m,null,C,S,P,A,F);else break;L--,U--}if(E>L){if(E<=U){const z=U+1,J=zU)for(;E<=L;)Ie(u[E],C,S,!0),E++;else{const z=E,J=E,ee=new Map;for(E=J;E<=U;E++){const be=h[E]=F?Ye(h[E]):Ee(h[E]);be.key!=null&&ee.set(be.key,E)}let Z,oe=0;const Re=U-J+1;let gt=!1,is=0;const Lt=new Array(Re);for(E=0;E=Re){Ie(be,C,S,!0);continue}let Pe;if(be.key!=null)Pe=ee.get(be.key);else for(Z=J;Z<=U;Z++)if(Lt[Z-J]===0&&Ne(be,h[Z])){Pe=Z;break}Pe===void 0?Ie(be,C,S,!0):(Lt[Pe-J]=E+1,Pe>=is?is=Pe:gt=!0,x(be,h[Pe],m,null,C,S,P,A,F),oe++)}const os=gt?mc(Lt):yt;for(Z=os.length-1,E=Re-1;E>=0;E--){const be=J+E,Pe=h[be],ls=be+1{const{el:S,type:P,transition:A,children:F,shapeFlag:E}=u;if(E&6){nt(u.component.subTree,h,m,w);return}if(E&128){u.suspense.move(h,m,w);return}if(E&64){P.move(u,h,m,pt);return}if(P===ye){r(S,h,m);for(let L=0;LA.enter(S),C);else{const{leave:L,delayLeave:U,afterLeave:z}=A,J=()=>r(S,h,m),ee=()=>{L(S,()=>{J(),z&&z()})};U?U(S,J,ee):ee()}else r(S,h,m)},Ie=(u,h,m,w=!1,C=!1)=>{const{type:S,props:P,ref:A,children:F,dynamicChildren:E,shapeFlag:j,patchFlag:L,dirs:U}=u;if(A!=null&&Pn(A,null,m,u,!0),j&256){h.ctx.deactivate(u);return}const z=j&1&&U,J=!Ct(u);let ee;if(J&&(ee=P&&P.onVnodeBeforeUnmount)&&Ce(ee,h,u),j&6)To(u.component,m,w);else{if(j&128){u.suspense.unmount(m,w);return}z&&Me(u,null,h,"beforeUnmount"),j&64?u.type.remove(u,h,m,C,pt,w):E&&(S!==ye||L>0&&L&64)?$e(E,h,m,!1,!0):(S===ye&&L&384||!C&&j&16)&&$e(F,h,m),w&&rs(u)}(J&&(ee=P&&P.onVnodeUnmounted)||z)&&me(()=>{ee&&Ce(ee,h,u),z&&Me(u,null,h,"unmounted")},m)},rs=u=>{const{type:h,el:m,anchor:w,transition:C}=u;if(h===ye){xo(m,w);return}if(h===Kt){p(u);return}const S=()=>{s(m),C&&!C.persisted&&C.afterLeave&&C.afterLeave()};if(u.shapeFlag&1&&C&&!C.persisted){const{leave:P,delayLeave:A}=C,F=()=>P(m,S);A?A(u.el,S,F):F()}else S()},xo=(u,h)=>{let m;for(;u!==h;)m=g(u),s(u),u=m;s(h)},To=(u,h,m)=>{const{bum:w,scope:C,update:S,subTree:P,um:A}=u;w&&wn(w),C.stop(),S&&(S.active=!1,Ie(P,u,h,m)),A&&me(A,h),me(()=>{u.isUnmounted=!0},h),h&&h.pendingBranch&&!h.isUnmounted&&u.asyncDep&&!u.asyncResolved&&u.suspenseId===h.pendingId&&(h.deps--,h.deps===0&&h.resolve())},$e=(u,h,m,w=!1,C=!1,S=0)=>{for(let P=S;Pu.shapeFlag&6?on(u.component.subTree):u.shapeFlag&128?u.suspense.next():g(u.anchor||u.el),ss=(u,h,m)=>{u==null?h._vnode&&Ie(h._vnode,null,null,!0):x(h._vnode||null,u,h,null,null,null,m),ys(),Sn(),h._vnode=u},pt={p:x,um:Ie,m:nt,r:rs,mt:ne,mc:_,pc:K,pbc:R,n:on,o:e};let Qn,Zn;return t&&([Qn,Zn]=t(pt)),{render:ss,hydrate:Qn,createApp:oc(ss,Qn)}}function rt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function zi(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Xr(e,t,n=!1){const r=e.children,s=t.children;if(D(r)&&D(s))for(let i=0;i>1,e[n[l]]0&&(t[r]=n[i-1]),n[i]=r)}}for(i=n.length,o=n[i-1];i-- >0;)n[i]=o,o=t[o];return n}const yc=e=>e.__isTeleport,Ut=e=>e&&(e.disabled||e.disabled===""),Fs=e=>typeof SVGElement<"u"&&e instanceof SVGElement,vr=(e,t)=>{const n=e&&e.to;return ie(n)?t?t(n):null:n},_c={__isTeleport:!0,process(e,t,n,r,s,i,o,l,c,a){const{mc:f,pc:d,pbc:g,o:{insert:b,querySelector:v,createText:x,createComment:N}}=a,k=Ut(t.props);let{shapeFlag:H,children:y,dynamicChildren:p}=t;if(e==null){const T=t.el=x(""),B=t.anchor=x("");b(T,n,r),b(B,n,r);const M=t.target=vr(t.props,v),_=t.targetAnchor=x("");M&&(b(_,M),o=o||Fs(M));const O=(R,W)=>{H&16&&f(y,R,W,s,i,o,l,c)};k?O(n,B):M&&O(M,_)}else{t.el=e.el;const T=t.anchor=e.anchor,B=t.target=e.target,M=t.targetAnchor=e.targetAnchor,_=Ut(e.props),O=_?n:B,R=_?T:M;if(o=o||Fs(B),p?(g(e.dynamicChildren,p,O,s,i,o,l),Xr(e,t,!0)):c||d(e,t,O,R,s,i,o,l,!1),k)_?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):mn(t,n,T,a,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const W=t.target=vr(t.props,v);W&&mn(t,W,null,a,0)}else _&&mn(t,B,M,a,1)}Yi(t)},remove(e,t,n,r,{um:s,o:{remove:i}},o){const{shapeFlag:l,children:c,anchor:a,targetAnchor:f,target:d,props:g}=e;if(d&&i(f),o&&i(a),l&16){const b=o||!Ut(g);for(let v=0;v0?Te||yt:null,Ji(),St>0&&Te&&Te.push(e),e}function hu(e,t,n,r,s,i){return Xi(Gi(e,t,n,r,s,i,!0))}function Qi(e,t,n,r,s){return Xi(se(e,t,n,r,s,!0))}function Xt(e){return e?e.__v_isVNode===!0:!1}function Ne(e,t){return e.type===t.type&&e.key===t.key}const Jn="__vInternal",Zi=({key:e})=>e??null,Cn=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?ie(e)||ae(e)||V(e)?{i:de,r:e,k:t,f:!!n}:e:null);function Gi(e,t=null,n=null,r=0,s=null,i=e===ye?0:1,o=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Zi(t),ref:t&&Cn(t),scopeId:Vn,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:i,patchFlag:r,dynamicProps:s,dynamicChildren:null,appContext:null,ctx:de};return l?(Zr(c,n),i&128&&e.normalize(c)):n&&(c.shapeFlag|=ie(n)?8:16),St>0&&!o&&Te&&(c.patchFlag>0||i&6)&&c.patchFlag!==32&&Te.push(c),c}const se=vc;function vc(e,t=null,n=null,r=0,s=null,i=!1){if((!e||e===Oi)&&(e=ge),Xt(e)){const l=et(e,t,!0);return n&&Zr(l,n),St>0&&!i&&Te&&(l.shapeFlag&6?Te[Te.indexOf(e)]=l:Te.push(l)),l.patchFlag|=-2,l}if(Fc(e)&&(e=e.__vccOpts),t){t=wc(t);let{class:l,style:c}=t;l&&!ie(l)&&(t.class=Ir(l)),G(c)&&(Ci(c)&&!D(c)&&(c=fe({},c)),t.style=Fr(c))}const o=ie(e)?1:Il(e)?128:yc(e)?64:G(e)?4:V(e)?2:0;return Gi(e,t,n,r,s,o,i,!0)}function wc(e){return e?Ci(e)||Jn in e?fe({},e):e:null}function et(e,t,n=!1){const{props:r,ref:s,patchFlag:i,children:o}=e,l=t?Cc(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&Zi(l),ref:t&&t.ref?n&&s?D(s)?s.concat(Cn(t)):[s,Cn(t)]:Cn(t):s,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ye?i===-1?16:i|16:i,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&et(e.ssContent),ssFallback:e.ssFallback&&et(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function eo(e=" ",t=0){return se(Rt,null,e,t)}function pu(e,t){const n=se(Kt,null,e);return n.staticCount=t,n}function gu(e="",t=!1){return t?(Qr(),Qi(ge,null,e)):se(ge,null,e)}function Ee(e){return e==null||typeof e=="boolean"?se(ge):D(e)?se(ye,null,e.slice()):typeof e=="object"?Ye(e):se(Rt,null,String(e))}function Ye(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:et(e)}function Zr(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(D(t))n=16;else if(typeof t=="object")if(r&65){const s=t.default;s&&(s._c&&(s._d=!1),Zr(e,s()),s._c&&(s._d=!0));return}else{n=32;const s=t._;!s&&!(Jn in t)?t._ctx=de:s===3&&de&&(de.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else V(t)?(t={default:t,_ctx:de},n=32):(t=String(t),r&64?(n=16,t=[eo(t)]):n=8);e.children=t,e.shapeFlag|=n}function Cc(...e){const t={};for(let n=0;nce||de;let Gr,mt,Ps="__VUE_INSTANCE_SETTERS__";(mt=cr()[Ps])||(mt=cr()[Ps]=[]),mt.push(e=>ce=e),Gr=e=>{mt.length>1?mt.forEach(t=>t(e)):mt[0](e)};const tt=e=>{Gr(e),e.scope.on()},Ze=()=>{ce&&ce.scope.off(),Gr(null)};function to(e){return e.vnode.shapeFlag&4}let Ot=!1;function Ac(e,t=!1){Ot=t;const{props:n,children:r}=e.vnode,s=to(e);cc(e,n,s,t),fc(e,r);const i=s?Rc(e,t):void 0;return Ot=!1,i}function Rc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Dt(new Proxy(e.ctx,Zl));const{setup:r}=n;if(r){const s=e.setupContext=r.length>1?ro(e):null;tt(e),Ft();const i=Xe(r,e,0,[e.props,s]);if(It(),Ze(),Sr(i)){if(i.then(Ze,Ze),t)return i.then(o=>{wr(e,o,t)}).catch(o=>{Pt(o,e,0)});e.asyncDep=i}else wr(e,i,t)}else no(e,t)}function wr(e,t,n){V(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:G(t)&&(e.setupState=xi(t)),no(e,n)}let Ms;function no(e,t,n){const r=e.type;if(!e.render){if(!t&&Ms&&!r.render){const s=r.template||Yr(e).template;if(s){const{isCustomElement:i,compilerOptions:o}=e.appContext.config,{delimiters:l,compilerOptions:c}=r,a=fe(fe({isCustomElement:i,delimiters:l},o),c);r.render=Ms(s,a)}}e.render=r.render||Oe}{tt(e),Ft();try{ec(e)}finally{It(),Ze()}}}function Sc(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return _e(e,"get","$attrs"),t[n]}}))}function ro(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Sc(e)},slots:e.slots,emit:e.emit,expose:t}}function Xn(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(xi(Dt(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in jt)return jt[n](e)},has(t,n){return n in t||n in jt}}))}function Oc(e,t=!0){return V(e)?e.displayName||e.name:e.name||t&&e.__name}function Fc(e){return V(e)&&"__vccOpts"in e}const le=(e,t)=>vl(e,t,Ot);function Cr(e,t,n){const r=arguments.length;return r===2?G(t)&&!D(t)?Xt(t)?se(e,null,[t]):se(e,t):se(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&Xt(n)&&(n=[n]),se(e,t,n))}const Ic=Symbol.for("v-scx"),Pc=()=>Et(Ic),Mc="3.3.8",Lc="http://www.w3.org/2000/svg",lt=typeof document<"u"?document:null,Ls=lt&<.createElement("template"),Nc={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const s=t?lt.createElementNS(Lc,e):lt.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&s.setAttribute("multiple",r.multiple),s},createText:e=>lt.createTextNode(e),createComment:e=>lt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>lt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,s,i){const o=n?n.previousSibling:t.lastChild;if(s&&(s===i||s.nextSibling))for(;t.insertBefore(s.cloneNode(!0),n),!(s===i||!(s=s.nextSibling)););else{Ls.innerHTML=r?`${e}`:e;const l=Ls.content;if(r){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Ve="transition",Nt="animation",Qt=Symbol("_vtc"),so=(e,{slots:t})=>Cr(jl,Bc(e),t);so.displayName="Transition";const io={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};so.props=fe({},Mi,io);const st=(e,t=[])=>{D(e)?e.forEach(n=>n(...t)):e&&e(...t)},Ns=e=>e?D(e)?e.some(t=>t.length>1):e.length>1:!1;function Bc(e){const t={};for(const I in e)I in io||(t[I]=e[I]);if(e.css===!1)return t;const{name:n="v",type:r,duration:s,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:a=o,appearToClass:f=l,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:g=`${n}-leave-active`,leaveToClass:b=`${n}-leave-to`}=e,v=Hc(s),x=v&&v[0],N=v&&v[1],{onBeforeEnter:k,onEnter:H,onEnterCancelled:y,onLeave:p,onLeaveCancelled:T,onBeforeAppear:B=k,onAppear:M=H,onAppearCancelled:_=y}=t,O=(I,q,ne)=>{it(I,q?f:l),it(I,q?a:o),ne&&ne()},R=(I,q)=>{I._isLeaving=!1,it(I,d),it(I,b),it(I,g),q&&q()},W=I=>(q,ne)=>{const re=I?M:H,$=()=>O(q,I,ne);st(re,[q,$]),Bs(()=>{it(q,I?c:i),qe(q,I?f:l),Ns(re)||Hs(q,r,x,$)})};return fe(t,{onBeforeEnter(I){st(k,[I]),qe(I,i),qe(I,o)},onBeforeAppear(I){st(B,[I]),qe(I,c),qe(I,a)},onEnter:W(!1),onAppear:W(!0),onLeave(I,q){I._isLeaving=!0;const ne=()=>R(I,q);qe(I,d),Dc(),qe(I,g),Bs(()=>{I._isLeaving&&(it(I,d),qe(I,b),Ns(p)||Hs(I,r,N,ne))}),st(p,[I,ne])},onEnterCancelled(I){O(I,!1),st(y,[I])},onAppearCancelled(I){O(I,!0),st(_,[I])},onLeaveCancelled(I){R(I),st(T,[I])}})}function Hc(e){if(e==null)return null;if(G(e))return[rr(e.enter),rr(e.leave)];{const t=rr(e);return[t,t]}}function rr(e){return ci(e)}function qe(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Qt]||(e[Qt]=new Set)).add(t)}function it(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const n=e[Qt];n&&(n.delete(t),n.size||(e[Qt]=void 0))}function Bs(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let $c=0;function Hs(e,t,n,r){const s=e._endId=++$c,i=()=>{s===e._endId&&r()};if(n)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=kc(e,t);if(!o)return r();const a=o+"end";let f=0;const d=()=>{e.removeEventListener(a,g),i()},g=b=>{b.target===e&&++f>=c&&d()};setTimeout(()=>{f(n[v]||"").split(", "),s=r(`${Ve}Delay`),i=r(`${Ve}Duration`),o=$s(s,i),l=r(`${Nt}Delay`),c=r(`${Nt}Duration`),a=$s(l,c);let f=null,d=0,g=0;t===Ve?o>0&&(f=Ve,d=o,g=i.length):t===Nt?a>0&&(f=Nt,d=a,g=c.length):(d=Math.max(o,a),f=d>0?o>a?Ve:Nt:null,g=f?f===Ve?i.length:c.length:0);const b=f===Ve&&/\b(transform|all)(,|$)/.test(r(`${Ve}Property`).toString());return{type:f,timeout:d,propCount:g,hasTransform:b}}function $s(e,t){for(;e.lengthks(n)+ks(e[r])))}function ks(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function Dc(){return document.body.offsetHeight}function jc(e,t,n){const r=e[Qt];r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const es=Symbol("_vod"),mu={beforeMount(e,{value:t},{transition:n}){e[es]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):Bt(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:r}){!t!=!n&&(r?t?(r.beforeEnter(e),Bt(e,!0),r.enter(e)):r.leave(e,()=>{Bt(e,!1)}):Bt(e,t))},beforeUnmount(e,{value:t}){Bt(e,t)}};function Bt(e,t){e.style.display=t?e[es]:"none"}function Uc(e,t,n){const r=e.style,s=ie(n);if(n&&!s){if(t&&!ie(t))for(const i in t)n[i]==null&&Er(r,i,"");for(const i in n)Er(r,i,n[i])}else{const i=r.display;s?t!==n&&(r.cssText=n):t&&e.removeAttribute("style"),es in e&&(r.display=i)}}const Ds=/\s*!important$/;function Er(e,t,n){if(D(n))n.forEach(r=>Er(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=Kc(e,t);Ds.test(n)?e.setProperty(ht(r),n.replace(Ds,""),"important"):e[r]=n}}const js=["Webkit","Moz","ms"],sr={};function Kc(e,t){const n=sr[t];if(n)return n;let r=Be(t);if(r!=="filter"&&r in e)return sr[t]=r;r=Hn(r);for(let s=0;sir||(Jc.then(()=>ir=0),ir=Date.now());function Qc(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Ae(Zc(r,n.value),t,5,[r])};return n.value=e,n.attached=Xc(),n}function Zc(e,t){if(D(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>s=>!s._stopped&&r&&r(s))}else return t}const Vs=/^on[a-z]/,Gc=(e,t,n,r,s=!1,i,o,l,c)=>{t==="class"?jc(e,r,s):t==="style"?Uc(e,n,r):en(t)?Ar(t)||zc(e,t,n,r,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):ea(e,t,r,s))?Vc(e,t,r,i,o,l,c):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),Wc(e,t,r,s))};function ea(e,t,n,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&Vs.test(t)&&V(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Vs.test(t)&&ie(n)?!1:t in e}const Mn=e=>{const t=e.props["onUpdate:modelValue"]||!1;return D(t)?n=>wn(t,n):t};function ta(e){e.target.composing=!0}function qs(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const xt=Symbol("_assign"),yu={created(e,{modifiers:{lazy:t,trim:n,number:r}},s){e[xt]=Mn(s);const i=r||s.props&&s.props.type==="number";ct(e,t?"change":"input",o=>{if(o.target.composing)return;let l=e.value;n&&(l=l.trim()),i&&(l=Tn(l)),e[xt](l)}),n&&ct(e,"change",()=>{e.value=e.value.trim()}),t||(ct(e,"compositionstart",ta),ct(e,"compositionend",qs),ct(e,"change",qs))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:r,number:s}},i){if(e[xt]=Mn(i),e.composing||document.activeElement===e&&e.type!=="range"&&(n||r&&e.value.trim()===t||(s||e.type==="number")&&Tn(e.value)===t))return;const o=t??"";e.value!==o&&(e.value=o)}},_u={deep:!0,created(e,{value:t,modifiers:{number:n}},r){const s=Nn(t);ct(e,"change",()=>{const i=Array.prototype.filter.call(e.options,o=>o.selected).map(o=>n?Tn(Ln(o)):Ln(o));e[xt](e.multiple?s?new Set(i):i:i[0])}),e[xt]=Mn(r)},mounted(e,{value:t}){zs(e,t)},beforeUpdate(e,t,n){e[xt]=Mn(n)},updated(e,{value:t}){zs(e,t)}};function zs(e,t){const n=e.multiple;if(!(n&&!D(t)&&!Nn(t))){for(let r=0,s=e.options.length;r-1:i.selected=t.has(o);else if($n(Ln(i),t)){e.selectedIndex!==r&&(e.selectedIndex=r);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function Ln(e){return"_value"in e?e._value:e.value}const na=["ctrl","shift","alt","meta"],ra={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>na.some(n=>e[`${n}Key`]&&!t.includes(n))},bu=(e,t)=>(n,...r)=>{for(let s=0;sn=>{if(!("key"in n))return;const r=ht(n.key);if(t.some(s=>s===r||sa[s]===r))return e(n)},oo=fe({patchProp:Gc},Nc);let Vt,Ys=!1;function ia(){return Vt||(Vt=pc(oo))}function oa(){return Vt=Ys?Vt:gc(oo),Ys=!0,Vt}const wu=(...e)=>{const t=ia().createApp(...e),{mount:n}=t;return t.mount=r=>{const s=lo(r);if(!s)return;const i=t._component;!V(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.innerHTML="";const o=n(s,!1,s instanceof SVGElement);return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),o},t},Cu=(...e)=>{const t=oa().createApp(...e),{mount:n}=t;return t.mount=r=>{const s=lo(r);if(s)return n(s,!0,s instanceof SVGElement)},t};function lo(e){return ie(e)?document.querySelector(e):e}const Eu=(e,t)=>{const n=e.__vccOpts||e;for(const[r,s]of t)n[r]=s;return n},la="modulepreload",ca=function(e){return"/zerdocs/"+e},Js={},xu=function(t,n,r){if(!n||n.length===0)return t();const s=document.getElementsByTagName("link");return Promise.all(n.map(i=>{if(i=ca(i),i in Js)return;Js[i]=!0;const o=i.endsWith(".css"),l=o?'[rel="stylesheet"]':"";if(!!r)for(let f=s.length-1;f>=0;f--){const d=s[f];if(d.href===i&&(!o||d.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${i}"]${l}`))return;const a=document.createElement("link");if(a.rel=o?"stylesheet":la,o||(a.as="script",a.crossOrigin=""),a.href=i,document.head.appendChild(a),o)return new Promise((f,d)=>{a.addEventListener("load",f),a.addEventListener("error",()=>d(new Error(`Unable to preload CSS for ${i}`)))})})).then(()=>t()).catch(i=>{const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=i,window.dispatchEvent(o),!o.defaultPrevented)throw i})},aa=window.__VP_SITE_DATA__;function ts(e){return fi()?(Uo(e),!0):!1}function Fe(e){return typeof e=="function"?e():jr(e)}function Tu(e,t){const n=(t==null?void 0:t.computedGetter)===!1?jr:Fe;return function(...r){return le(()=>e.apply(this,r.map(s=>n(s))))}}const co=typeof window<"u"&&typeof document<"u",ua=Object.prototype.toString,fa=e=>ua.call(e)==="[object Object]",Zt=()=>{},Xs=da();function da(){var e;return co&&((e=window==null?void 0:window.navigator)==null?void 0:e.userAgent)&&/iP(ad|hone|od)/.test(window.navigator.userAgent)}function ha(e,t){function n(...r){return new Promise((s,i)=>{Promise.resolve(e(()=>t.apply(this,r),{fn:t,thisArg:this,args:r})).then(s).catch(i)})}return n}const ao=e=>e();function pa(e,t={}){let n,r,s=Zt;const i=l=>{clearTimeout(l),s(),s=Zt};return l=>{const c=Fe(e),a=Fe(t.maxWait);return n&&i(n),c<=0||a!==void 0&&a<=0?(r&&(i(r),r=null),Promise.resolve(l())):new Promise((f,d)=>{s=t.rejectOnCancel?d:f,a&&!r&&(r=setTimeout(()=>{n&&i(n),r=null,f(l())},a)),n=setTimeout(()=>{r&&i(r),r=null,f(l())},c)})}}function ga(e=ao){const t=ue(!0);function n(){t.value=!1}function r(){t.value=!0}const s=(...i)=>{t.value&&e(...i)};return{isActive:jn(t),pause:n,resume:r,eventFilter:s}}function uo(...e){if(e.length!==1)return yl(...e);const t=e[0];return typeof t=="function"?jn(pl(()=>({get:t,set:Zt}))):ue(t)}function fo(e,t,n={}){const{eventFilter:r=ao,...s}=n;return Qe(e,ha(r,t),s)}function ma(e,t,n={}){const{eventFilter:r,...s}=n,{eventFilter:i,pause:o,resume:l,isActive:c}=ga(r);return{stop:fo(e,t,{...s,eventFilter:i}),pause:o,resume:l,isActive:c}}function ya(e,t=!0){rn()?Mt(e):t?e():Un(e)}function Au(e,t,n={}){const{debounce:r=0,maxWait:s=void 0,...i}=n;return fo(e,t,{...i,eventFilter:pa(r,{maxWait:s})})}function Ru(e,t,n){let r;ae(n)?r={evaluating:n}:r=n||{};const{lazy:s=!1,evaluating:i=void 0,shallow:o=!0,onError:l=Zt}=r,c=ue(!s),a=o?Dr(t):ue(t);let f=0;return qr(async d=>{if(!c.value)return;f++;const g=f;let b=!1;i&&Promise.resolve().then(()=>{i.value=!0});try{const v=await e(x=>{d(()=>{i&&(i.value=!1),b||x()})});g===f&&(a.value=v)}catch(v){l(v)}finally{i&&g===f&&(i.value=!1),b=!0}}),s?le(()=>(c.value=!0,a.value)):a}function ho(e){var t;const n=Fe(e);return(t=n==null?void 0:n.$el)!=null?t:n}const je=co?window:void 0;function Gt(...e){let t,n,r,s;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,r,s]=e,t=je):[t,n,r,s]=e,!t)return Zt;Array.isArray(n)||(n=[n]),Array.isArray(r)||(r=[r]);const i=[],o=()=>{i.forEach(f=>f()),i.length=0},l=(f,d,g,b)=>(f.addEventListener(d,g,b),()=>f.removeEventListener(d,g,b)),c=Qe(()=>[ho(t),Fe(s)],([f,d])=>{if(o(),!f)return;const g=fa(d)?{...d}:d;i.push(...n.flatMap(b=>r.map(v=>l(f,b,v,g))))},{immediate:!0,flush:"post"}),a=()=>{c(),o()};return ts(a),a}function _a(e){return typeof e=="function"?e:typeof e=="string"?t=>t.key===e:Array.isArray(e)?t=>e.includes(t.key):()=>!0}function Su(...e){let t,n,r={};e.length===3?(t=e[0],n=e[1],r=e[2]):e.length===2?typeof e[1]=="object"?(t=!0,n=e[0],r=e[1]):(t=e[0],n=e[1]):(t=!0,n=e[0]);const{target:s=je,eventName:i="keydown",passive:o=!1,dedupe:l=!1}=r,c=_a(t);return Gt(s,i,f=>{f.repeat&&Fe(l)||c(f)&&n(f)},o)}function ba(){const e=ue(!1);return rn()&&Mt(()=>{e.value=!0}),e}function va(e){const t=ba();return le(()=>(t.value,!!e()))}function wa(e,t={}){const{window:n=je}=t,r=va(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let s;const i=ue(!1),o=a=>{i.value=a.matches},l=()=>{s&&("removeEventListener"in s?s.removeEventListener("change",o):s.removeListener(o))},c=qr(()=>{r.value&&(l(),s=n.matchMedia(Fe(e)),"addEventListener"in s?s.addEventListener("change",o):s.addListener(o),i.value=s.matches)});return ts(()=>{c(),l(),s=void 0}),i}const yn=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},_n="__vueuse_ssr_handlers__",Ca=Ea();function Ea(){return _n in yn||(yn[_n]=yn[_n]||{}),yn[_n]}function po(e,t){return Ca[e]||t}function xa(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const Ta={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},Qs="vueuse-storage";function ns(e,t,n,r={}){var s;const{flush:i="pre",deep:o=!0,listenToStorageChanges:l=!0,writeDefaults:c=!0,mergeDefaults:a=!1,shallow:f,window:d=je,eventFilter:g,onError:b=_=>{console.error(_)}}=r,v=(f?Dr:ue)(t);if(!n)try{n=po("getDefaultStorage",()=>{var _;return(_=je)==null?void 0:_.localStorage})()}catch(_){b(_)}if(!n)return v;const x=Fe(t),N=xa(x),k=(s=r.serializer)!=null?s:Ta[N],{pause:H,resume:y}=ma(v,()=>p(v.value),{flush:i,deep:o,eventFilter:g});return d&&l&&(Gt(d,"storage",M),Gt(d,Qs,B)),M(),v;function p(_){try{if(_==null)n.removeItem(e);else{const O=k.write(_),R=n.getItem(e);R!==O&&(n.setItem(e,O),d&&d.dispatchEvent(new CustomEvent(Qs,{detail:{key:e,oldValue:R,newValue:O,storageArea:n}})))}}catch(O){b(O)}}function T(_){const O=_?_.newValue:n.getItem(e);if(O==null)return c&&x!==null&&n.setItem(e,k.write(x)),x;if(!_&&a){const R=k.read(O);return typeof a=="function"?a(R,x):N==="object"&&!Array.isArray(R)?{...x,...R}:R}else return typeof O!="string"?O:k.read(O)}function B(_){M(_.detail)}function M(_){if(!(_&&_.storageArea!==n)){if(_&&_.key==null){v.value=x;return}if(!(_&&_.key!==e)){H();try{(_==null?void 0:_.newValue)!==k.write(v.value)&&(v.value=T(_))}catch(O){b(O)}finally{_?Un(y):y()}}}}}function Aa(e){return wa("(prefers-color-scheme: dark)",e)}function Ra(e={}){const{selector:t="html",attribute:n="class",initialValue:r="auto",window:s=je,storage:i,storageKey:o="vueuse-color-scheme",listenToStorageChanges:l=!0,storageRef:c,emitAuto:a,disableTransition:f=!0}=e,d={auto:"",light:"light",dark:"dark",...e.modes||{}},g=Aa({window:s}),b=le(()=>g.value?"dark":"light"),v=c||(o==null?uo(r):ns(o,r,i,{window:s,listenToStorageChanges:l})),x=le(()=>v.value==="auto"?b.value:v.value),N=po("updateHTMLAttrs",(p,T,B)=>{const M=typeof p=="string"?s==null?void 0:s.document.querySelector(p):ho(p);if(!M)return;let _;if(f){_=s.document.createElement("style");const O="*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";_.appendChild(document.createTextNode(O)),s.document.head.appendChild(_)}if(T==="class"){const O=B.split(/\s/g);Object.values(d).flatMap(R=>(R||"").split(/\s/g)).filter(Boolean).forEach(R=>{O.includes(R)?M.classList.add(R):M.classList.remove(R)})}else M.setAttribute(T,B);f&&(s.getComputedStyle(_).opacity,document.head.removeChild(_))});function k(p){var T;N(t,n,(T=d[p])!=null?T:p)}function H(p){e.onChanged?e.onChanged(p,k):k(p)}Qe(x,H,{flush:"post",immediate:!0}),ya(()=>H(x.value));const y=le({get(){return a?v.value:x.value},set(p){v.value=p}});try{return Object.assign(y,{store:v,system:b,state:x})}catch{return y}}function Sa(e={}){const{valueDark:t="dark",valueLight:n=""}=e,r=Ra({...e,onChanged:(i,o)=>{var l;e.onChanged?(l=e.onChanged)==null||l.call(e,i==="dark",o,i):o(i)},modes:{dark:t,light:n}});return le({get(){return r.value==="dark"},set(i){const o=i?"dark":"light";r.system.value===o?r.value="auto":r.value=o}})}function or(e){return typeof Window<"u"&&e instanceof Window?e.document.documentElement:typeof Document<"u"&&e instanceof Document?e.documentElement:e}function Ou(e,t,n={}){const{window:r=je}=n;return ns(e,t,r==null?void 0:r.localStorage,n)}function go(e){const t=window.getComputedStyle(e);if(t.overflowX==="scroll"||t.overflowY==="scroll"||t.overflowX==="auto"&&e.clientWidth1?!0:(t.preventDefault&&t.preventDefault(),!1)}function Fu(e,t=!1){const n=ue(t);let r=null,s;Qe(uo(e),l=>{const c=or(Fe(l));if(c){const a=c;s=a.style.overflow,n.value&&(a.style.overflow="hidden")}},{immediate:!0});const i=()=>{const l=or(Fe(e));!l||n.value||(Xs&&(r=Gt(l,"touchmove",c=>{Oa(c)},{passive:!1})),l.style.overflow="hidden",n.value=!0)},o=()=>{const l=or(Fe(e));!l||!n.value||(Xs&&(r==null||r()),l.style.overflow=s,n.value=!1)};return ts(o),le({get(){return n.value},set(l){l?i():o()}})}function Iu(e,t,n={}){const{window:r=je}=n;return ns(e,t,r==null?void 0:r.sessionStorage,n)}function Pu(e={}){const{window:t=je}=e;if(!t)return{x:ue(0),y:ue(0)};const n=ue(t.scrollX),r=ue(t.scrollY);return Gt(t,"scroll",()=>{n.value=t.scrollX,r.value=t.scrollY},{capture:!1,passive:!0}),{x:n,y:r}}const mo=/^[a-z]+:/i,Fa="vitepress-theme-appearance",yo=/#.*$/,Ia=/(index)?\.(md|html)$/,xe=typeof document<"u",_o={relativePath:"",filePath:"",title:"404",description:"Not Found",headers:[],frontmatter:{sidebar:!1,layout:"page"},lastUpdated:0,isNotFound:!0};function Pa(e,t,n=!1){if(t===void 0)return!1;if(e=Zs(`/${e}`),n)return new RegExp(t).test(e);if(Zs(t)!==e)return!1;const r=t.match(yo);return r?(xe?location.hash:"")===r[0]:!0}function Zs(e){return decodeURI(e).replace(yo,"").replace(Ia,"")}function Ma(e){return mo.test(e)}function La(e,t){var r,s,i,o,l,c,a;const n=Object.keys(e.locales).find(f=>f!=="root"&&!Ma(f)&&Pa(t,`/${f}/`,!0))||"root";return Object.assign({},e,{localeIndex:n,lang:((r=e.locales[n])==null?void 0:r.lang)??e.lang,dir:((s=e.locales[n])==null?void 0:s.dir)??e.dir,title:((i=e.locales[n])==null?void 0:i.title)??e.title,titleTemplate:((o=e.locales[n])==null?void 0:o.titleTemplate)??e.titleTemplate,description:((l=e.locales[n])==null?void 0:l.description)??e.description,head:vo(e.head,((c=e.locales[n])==null?void 0:c.head)??[]),themeConfig:{...e.themeConfig,...(a=e.locales[n])==null?void 0:a.themeConfig}})}function bo(e,t){const n=t.title||e.title,r=t.titleTemplate??e.titleTemplate;if(typeof r=="string"&&r.includes(":title"))return r.replace(/:title/g,n);const s=Na(e.title,r);return`${n}${s}`}function Na(e,t){return t===!1?"":t===!0||t===void 0?` | ${e}`:e===t?"":` | ${t}`}function Ba(e,t){const[n,r]=t;if(n!=="meta")return!1;const s=Object.entries(r)[0];return s==null?!1:e.some(([i,o])=>i===n&&o[s[0]]===s[1])}function vo(e,t){return[...e.filter(n=>!Ba(t,n)),...t]}const Ha=/[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g,$a=/^[a-z]:/i;function Gs(e){const t=$a.exec(e),n=t?t[0]:"";return n+e.slice(n.length).replace(Ha,"_").replace(/(^|\/)_+(?=[^/]*$)/,"$1")}const ka=Symbol(),ft=Dr(aa);function Mu(e){const t=le(()=>La(ft.value,e.data.relativePath)),n=t.value.appearance,r=n==="force-dark"?ue(!0):n?Sa({storageKey:Fa,initialValue:()=>typeof n=="string"?n:"auto",...typeof n=="object"?n:{}}):ue(!1);return{site:t,theme:le(()=>t.value.themeConfig),page:le(()=>e.data),frontmatter:le(()=>e.data.frontmatter),params:le(()=>e.data.params),lang:le(()=>t.value.lang),dir:le(()=>t.value.dir),localeIndex:le(()=>t.value.localeIndex||"root"),title:le(()=>bo(t.value,e.data)),description:le(()=>e.data.description||t.value.description),isDark:r}}function Da(){const e=Et(ka);if(!e)throw new Error("vitepress data not properly injected in app");return e}function ja(e,t){return`${e}${t}`.replace(/\/+/g,"/")}function ei(e){return mo.test(e)||!e.startsWith("/")?e:ja(ft.value.base,e)}function Ua(e){let t=e.replace(/\.html$/,"");if(t=decodeURIComponent(t),t=t.replace(/\/$/,"/index"),xe){const n="/zerdocs/";t=Gs(t.slice(n.length).replace(/\//g,"_")||"index")+".md";let r=__VP_HASH_MAP__[t.toLowerCase()];if(r||(t=t.endsWith("_index.md")?t.slice(0,-9)+".md":t.slice(0,-3)+"_index.md",r=__VP_HASH_MAP__[t.toLowerCase()]),!r)return null;t=`${n}assets/${t}.${r}.js`}else t=`./${Gs(t.slice(1).replace(/\//g,"_"))}.md.js`;return t}let En=[];function Lu(e){En.push(e),Yn(()=>{En=En.filter(t=>t!==e)})}const Ka=Symbol(),wo="http://a.com",Wa=()=>({path:"/",component:null,data:_o});function Nu(e,t){const n=Dn(Wa()),r={route:n,go:s};async function s(l=xe?location.href:"/"){var c,a;l=xr(l),await((c=r.onBeforeRouteChange)==null?void 0:c.call(r,l))!==!1&&(ri(l),await o(l),await((a=r.onAfterRouteChanged)==null?void 0:a.call(r,l)))}let i=null;async function o(l,c=0,a=!1){var g;if(await((g=r.onBeforePageLoad)==null?void 0:g.call(r,l))===!1)return;const f=new URL(l,wo),d=i=f.pathname;try{let b=await e(d);if(!b)throw new Error(`Page not found: ${d}`);if(i===d){i=null;const{default:v,__pageData:x}=b;if(!v)throw new Error(`Invalid route component: ${v}`);n.path=xe?d:ei(d),n.component=Dt(v),n.data=Dt(x),xe&&Un(()=>{let N=ft.value.base+x.relativePath.replace(/(?:(^|\/)index)?\.md$/,"$1");if(!ft.value.cleanUrls&&!N.endsWith("/")&&(N+=".html"),N!==f.pathname&&(f.pathname=N,l=N+f.search+f.hash,history.replaceState(null,"",l)),f.hash&&!c){let k=null;try{k=document.getElementById(decodeURIComponent(f.hash).slice(1))}catch(H){console.warn(H)}if(k){ti(k,f.hash);return}}window.scrollTo(0,c)})}}catch(b){if(!/fetch|Page not found/.test(b.message)&&!/^\/404(\.html|\/)?$/.test(l)&&console.error(b),!a)try{const v=await fetch(ft.value.base+"hashmap.json");window.__VP_HASH_MAP__=await v.json(),await o(l,c,!0);return}catch{}i===d&&(i=null,n.path=xe?d:ei(d),n.component=t?Dt(t):null,n.data=_o)}}return xe&&(window.addEventListener("click",l=>{if(l.target.closest("button"))return;const a=l.target.closest("a");if(a&&!a.closest(".vp-raw")&&(a instanceof SVGElement||!a.download)){const{target:f}=a,{href:d,origin:g,pathname:b,hash:v,search:x}=new URL(a.href instanceof SVGAnimatedString?a.href.animVal:a.href,a.baseURI),N=window.location,k=b.match(/\.\w+$/);!l.ctrlKey&&!l.shiftKey&&!l.altKey&&!l.metaKey&&!f&&g===N.origin&&!(k&&k[0]!==".html")&&(l.preventDefault(),b===N.pathname&&x===N.search?(v!==N.hash&&(history.pushState(null,"",v),window.dispatchEvent(new Event("hashchange"))),v?ti(a,v,a.classList.contains("header-anchor")):(ri(d),window.scrollTo(0,0))):s(d))}},{capture:!0}),window.addEventListener("popstate",l=>{o(xr(location.href),l.state&&l.state.scrollPosition||0)}),window.addEventListener("hashchange",l=>{l.preventDefault()})),r}function Va(){const e=Et(Ka);if(!e)throw new Error("useRouter() is called without provider.");return e}function Co(){return Va().route}function ti(e,t,n=!1){let r=null;try{r=e.classList.contains("header-anchor")?e:document.getElementById(decodeURIComponent(t).slice(1))}catch(s){console.warn(s)}if(r){let a=function(){!n||Math.abs(c-window.scrollY)>window.innerHeight?window.scrollTo(0,c):window.scrollTo({left:0,top:c,behavior:"smooth"})},s=ft.value.scrollOffset,i=0,o=24;if(typeof s=="object"&&"padding"in s&&(o=s.padding,s=s.selector),typeof s=="number")i=s;else if(typeof s=="string")i=ni(s,o);else if(Array.isArray(s))for(const f of s){const d=ni(f,o);if(d){i=d;break}}const l=parseInt(window.getComputedStyle(r).paddingTop,10),c=window.scrollY+r.getBoundingClientRect().top-i+l;requestAnimationFrame(a)}}function ni(e,t){const n=document.querySelector(e);if(!n)return 0;const r=n.getBoundingClientRect().bottom;return r<0?0:r+t}function ri(e){xe&&e!==xr(location.href)&&(history.replaceState({scrollPosition:window.scrollY},document.title),history.pushState(null,"",e))}function xr(e){const t=new URL(e,wo);return t.pathname=t.pathname.replace(/(^|\/)index(\.html)?$/,"$1"),ft.value.cleanUrls?t.pathname=t.pathname.replace(/\.html$/,""):!t.pathname.endsWith("/")&&!t.pathname.endsWith(".html")&&(t.pathname+=".html"),t.pathname+t.search+t.hash}const si=()=>En.forEach(e=>e()),Bu=zr({name:"VitePressContent",props:{as:{type:[Object,String],default:"div"}},setup(e){const t=Co(),{site:n}=Da();return()=>Cr(e.as,n.value.contentProps??{style:{position:"relative"}},[t.component?Cr(t.component,{onVnodeMounted:si,onVnodeUpdated:si}):"404 Page Not Found"])}}),Hu=zr({setup(e,{slots:t}){const n=ue(!1);return Mt(()=>{n.value=!0}),()=>n.value&&t.default?t.default():null}});function $u(){xe&&window.addEventListener("click",e=>{var n;const t=e.target;if(t.matches(".vp-code-group input")){const r=(n=t.parentElement)==null?void 0:n.parentElement;if(!r)return;const s=Array.from(r.querySelectorAll("input")).indexOf(t);if(s<0)return;const i=r.querySelector(".blocks");if(!i)return;const o=Array.from(i.children).find(a=>a.classList.contains("active"));if(!o)return;const l=i.children[s];if(!l||o===l)return;o.classList.remove("active"),l.classList.add("active");const c=r==null?void 0:r.querySelector(`label[for="${t.id}"]`);c==null||c.scrollIntoView({block:"nearest"})}})}function ku(){if(xe){const e=new WeakMap;window.addEventListener("click",t=>{var r;const n=t.target;if(n.matches('div[class*="language-"] > button.copy')){const s=n.parentElement,i=(r=n.nextElementSibling)==null?void 0:r.nextElementSibling;if(!s||!i)return;const o=/language-(shellscript|shell|bash|sh|zsh)/.test(s.className);let l="";i.querySelectorAll("span.line:not(.diff.remove)").forEach(c=>l+=(c.textContent||"")+` +`),l=l.slice(0,-1),o&&(l=l.replace(/^ *(\$|>) /gm,"").trim()),qa(l).then(()=>{n.classList.add("copied"),clearTimeout(e.get(n));const c=setTimeout(()=>{n.classList.remove("copied"),n.blur(),e.delete(n)},2e3);e.set(n,c)})}})}}async function qa(e){try{return navigator.clipboard.writeText(e)}catch{const t=document.createElement("textarea"),n=document.activeElement;t.value=e,t.setAttribute("readonly",""),t.style.contain="strict",t.style.position="absolute",t.style.left="-9999px",t.style.fontSize="12pt";const r=document.getSelection(),s=r?r.rangeCount>0&&r.getRangeAt(0):null;document.body.appendChild(t),t.select(),t.selectionStart=0,t.selectionEnd=e.length,document.execCommand("copy"),document.body.removeChild(t),s&&(r.removeAllRanges(),r.addRange(s)),n&&n.focus()}}function Du(e,t){let n=[],r=!0;const s=i=>{if(r){r=!1;return}const o=i.map(ii);n.forEach((l,c)=>{const a=o.findIndex(f=>f==null?void 0:f.isEqualNode(l??null));a!==-1?delete o[a]:(l==null||l.remove(),delete n[c])}),o.forEach(l=>l&&document.head.appendChild(l)),n=[...n,...o].filter(Boolean)};qr(()=>{const i=e.data,o=t.value,l=i&&i.description,c=i&&i.frontmatter.head||[],a=bo(o,i);a!==document.title&&(document.title=a);const f=l||o.description;let d=document.querySelector("meta[name=description]");d?d.getAttribute("content")!==f&&d.setAttribute("content",f):ii(["meta",{name:"description",content:f}]),s(vo(o.head,Ya(c)))})}function ii([e,t,n]){const r=document.createElement(e);for(const s in t)r.setAttribute(s,t[s]);return n&&(r.innerHTML=n),e==="script"&&!t.async&&(r.async=!1),r}function za(e){return e[0]==="meta"&&e[1]&&e[1].name==="description"}function Ya(e){return e.filter(t=>!za(t))}const lr=new Set,Eo=()=>document.createElement("link"),Ja=e=>{const t=Eo();t.rel="prefetch",t.href=e,document.head.appendChild(t)},Xa=e=>{const t=new XMLHttpRequest;t.open("GET",e,t.withCredentials=!0),t.send()};let bn;const Qa=xe&&(bn=Eo())&&bn.relList&&bn.relList.supports&&bn.relList.supports("prefetch")?Ja:Xa;function ju(){if(!xe||!window.IntersectionObserver)return;let e;if((e=navigator.connection)&&(e.saveData||/2g/.test(e.effectiveType)))return;const t=window.requestIdleCallback||setTimeout;let n=null;const r=()=>{n&&n.disconnect(),n=new IntersectionObserver(i=>{i.forEach(o=>{if(o.isIntersecting){const l=o.target;n.unobserve(l);const{pathname:c}=l;if(!lr.has(c)){lr.add(c);const a=Ua(c);a&&Qa(a)}}})}),t(()=>{document.querySelectorAll("#app a").forEach(i=>{const{hostname:o,pathname:l}=new URL(i.href instanceof SVGAnimatedString?i.href.animVal:i.href,i.baseURI),c=l.match(/\.\w+$/);c&&c[0]!==".html"||i.target!=="_blank"&&o===location.hostname&&(l!==location.pathname?n.observe(i):lr.add(l))})})};Mt(r);const s=Co();Qe(()=>s.path,r),Yn(()=>{n&&n.disconnect()})}export{au as $,su as A,zl as B,tu as C,lu as D,Dr as E,ye as F,Lu as G,se as H,nu as I,mo as J,Co as K,Cc as L,Et as M,Fr as N,Un as O,Pu as P,pu as Q,jn as R,Tu as S,so as T,yl as U,Su as V,ou as W,xu as X,Fu as Y,lc as Z,Eu as _,eo as a,vu as a0,bu as a1,uu as a2,fu as a3,iu as a4,yu as a5,_u as a6,Ql as a7,ru as a8,mu as a9,wu as aA,Cr as aa,Du as ab,Ka as ac,Mu as ad,ka as ae,Bu as af,Hu as ag,ft as ah,Cu as ai,Nu as aj,Ua as ak,ju as al,ku as am,$u as an,ho as ao,ts as ap,Ru as aq,Iu as ar,Ou as as,Au as at,Va as au,Gt as av,Hi as aw,ae as ax,du as ay,Dt as az,Qi as b,hu as c,zr as d,gu as e,ei as f,le as g,ue as h,Ma as i,Mt as j,Gi as k,jr as l,eu as m,Ir as n,Qr as o,Ga as p,Pa as q,cu as r,xe as s,Za as t,Da as u,wa as v,Al as w,Qe as x,qr as y,Yn as z}; diff --git a/assets/chunks/theme.1e9d2528.js b/assets/chunks/theme.1e9d2528.js new file mode 100644 index 00000000..3ff23a1c --- /dev/null +++ b/assets/chunks/theme.1e9d2528.js @@ -0,0 +1 @@ +import{d as b,o as a,c as i,r as u,n as T,a as x,t as L,_ as m,b as $,w as v,e as f,T as ce,u as ze,i as De,f as ue,g as k,h as M,j as G,k as c,l,p as H,m as z,q as O,s as q,v as re,x as U,y as te,z as de,A as Ve,B as Ee,C as j,F as N,D as A,E as _e,G as Y,H as h,I as F,J as we,K as se,L as Z,M as ne,N as Fe,O as Oe,P as Le,Q as Ge,R as Ue,S as je,U as Ke,V as ke,W as Re,X as qe,Y as Se,Z as Me,$ as We,a0 as Ye,a1 as Je,a2 as Xe}from"./framework.c53372a0.js";const Ze=b({__name:"VPBadge",props:{text:{},type:{default:"tip"}},setup(s){return(e,t)=>(a(),i("span",{class:T(["VPBadge",e.type])},[u(e.$slots,"default",{},()=>[x(L(e.text),1)],!0)],2))}});const Qe=m(Ze,[["__scopeId","data-v-9613cc9f"]]),et={key:0,class:"VPBackdrop"},tt=b({__name:"VPBackdrop",props:{show:{type:Boolean}},setup(s){return(e,t)=>(a(),$(ce,{name:"fade"},{default:v(()=>[e.show?(a(),i("div",et)):f("",!0)]),_:1}))}});const st=m(tt,[["__scopeId","data-v-c79a1216"]]),P=ze;function nt(s,e){let t,n=!1;return()=>{t&&clearTimeout(t),n?t=setTimeout(s,e):(s(),(n=!0)&&setTimeout(()=>n=!1,e))}}function le(s){return/^\//.test(s)?s:`/${s}`}function J(s){const{pathname:e,search:t,hash:n,protocol:o}=new URL(s,"http://a.com");if(De(s)||s.startsWith("#")||!o.startsWith("http")||/\.(?!html|md)\w+($|\?)/i.test(s))return s;const{site:r}=P(),d=e.endsWith("/")||e.endsWith(".html")?s:s.replace(/(?:(^\.+)\/)?.*$/,`$1${e.replace(/(\.md)?$/,r.value.cleanUrls?"":".html")}${t}${n}`);return ue(d)}function X({removeCurrent:s=!0,correspondingLink:e=!1}={}){const{site:t,localeIndex:n,page:o,theme:r}=P(),d=k(()=>{var _,g;return{label:(_=t.value.locales[n.value])==null?void 0:_.label,link:((g=t.value.locales[n.value])==null?void 0:g.link)||(n.value==="root"?"/":`/${n.value}/`)}});return{localeLinks:k(()=>Object.entries(t.value.locales).flatMap(([_,g])=>s&&d.value.label===g.label?[]:{text:g.label,link:ot(g.link||(_==="root"?"/":`/${_}/`),r.value.i18nRouting!==!1&&e,o.value.relativePath.slice(d.value.link.length-1),!t.value.cleanUrls)})),currentLang:d}}function ot(s,e,t,n){return e?s.replace(/\/$/,"")+le(t.replace(/(^|\/)index\.md$/,"$1").replace(/\.md$/,n?".html":"")):s}const at=s=>(H("data-v-f87ff6e4"),s=s(),z(),s),rt={class:"NotFound"},lt={class:"code"},it={class:"title"},ct=at(()=>c("div",{class:"divider"},null,-1)),ut={class:"quote"},dt={class:"action"},_t=["href","aria-label"],vt=b({__name:"NotFound",setup(s){const{site:e,theme:t}=P(),{localeLinks:n}=X({removeCurrent:!1}),o=M("/");return G(()=>{var d;const r=window.location.pathname.replace(e.value.base,"").replace(/(^.*?\/).*$/,"/$1");n.value.length&&(o.value=((d=n.value.find(({link:p})=>p.startsWith(r)))==null?void 0:d.link)||n.value[0].link)}),(r,d)=>{var p,_,g,V,y;return a(),i("div",rt,[c("p",lt,L(((p=l(t).notFound)==null?void 0:p.code)??"404"),1),c("h1",it,L(((_=l(t).notFound)==null?void 0:_.title)??"PAGE NOT FOUND"),1),ct,c("blockquote",ut,L(((g=l(t).notFound)==null?void 0:g.quote)??"But if you don't change your direction, and if you keep looking, you may end up where you are heading."),1),c("div",dt,[c("a",{class:"link",href:l(ue)(o.value),"aria-label":((V=l(t).notFound)==null?void 0:V.linkLabel)??"go to home"},L(((y=l(t).notFound)==null?void 0:y.linkText)??"Take me home"),9,_t)])])}}});const pt=m(vt,[["__scopeId","data-v-f87ff6e4"]]);function Ne(s,e){if(Array.isArray(s))return Q(s);if(s==null)return[];e=le(e);const t=Object.keys(s).sort((o,r)=>r.split("/").length-o.split("/").length).find(o=>e.startsWith(le(o))),n=t?s[t]:[];return Array.isArray(n)?Q(n):Q(n.items,n.base)}function ht(s){const e=[];let t=0;for(const n in s){const o=s[n];if(o.items){t=e.push(o);continue}e[t]||e.push({items:[]}),e[t].items.push(o)}return e}function ft(s){const e=[];function t(n){for(const o of n)o.text&&o.link&&e.push({text:o.text,link:o.link,docFooterText:o.docFooterText}),o.items&&t(o.items)}return t(s),e}function ie(s,e){return Array.isArray(e)?e.some(t=>ie(s,t)):O(s,e.link)?!0:e.items?ie(s,e.items):!1}function Q(s,e){return[...s].map(t=>{const n={...t},o=n.base||e;return o&&n.link&&(n.link=o+n.link),n.items&&(n.items=Q(n.items,o)),n})}function D(){const{frontmatter:s,page:e,theme:t}=P(),n=re("(min-width: 960px)"),o=M(!1),r=k(()=>{const B=t.value.sidebar,w=e.value.relativePath;return B?Ne(B,w):[]}),d=M(r.value);U(r,(B,w)=>{JSON.stringify(B)!==JSON.stringify(w)&&(d.value=r.value)});const p=k(()=>s.value.sidebar!==!1&&d.value.length>0&&s.value.layout!=="home"),_=k(()=>g?s.value.aside==null?t.value.aside==="left":s.value.aside==="left":!1),g=k(()=>s.value.layout==="home"?!1:s.value.aside!=null?!!s.value.aside:t.value.aside!==!1),V=k(()=>p.value&&n.value),y=k(()=>p.value?ht(d.value):[]);function I(){o.value=!0}function S(){o.value=!1}function C(){o.value?S():I()}return{isOpen:o,sidebar:d,sidebarGroups:y,hasSidebar:p,hasAside:g,leftAside:_,isSidebarEnabled:V,open:I,close:S,toggle:C}}function mt(s,e){let t;te(()=>{t=s.value?document.activeElement:void 0}),G(()=>{window.addEventListener("keyup",n)}),de(()=>{window.removeEventListener("keyup",n)});function n(o){o.key==="Escape"&&s.value&&(e(),t==null||t.focus())}}const Ie=M(q?location.hash:"");q&&window.addEventListener("hashchange",()=>{Ie.value=location.hash});function gt(s){const{page:e}=P(),t=M(!1),n=k(()=>s.value.collapsed!=null),o=k(()=>!!s.value.link),r=M(!1),d=()=>{r.value=O(e.value.relativePath,s.value.link)};U([e,s,Ie],d),G(d);const p=k(()=>r.value?!0:s.value.items?ie(e.value.relativePath,s.value.items):!1),_=k(()=>!!(s.value.items&&s.value.items.length));te(()=>{t.value=!!(n.value&&s.value.collapsed)}),Ve(()=>{(r.value||p.value)&&(t.value=!1)});function g(){n.value&&(t.value=!t.value)}return{collapsed:t,collapsible:n,isLink:o,isActiveLink:r,hasActiveLink:p,hasChildren:_,toggle:g}}function bt(){const{hasSidebar:s}=D(),e=re("(min-width: 960px)"),t=re("(min-width: 1280px)");return{isAsideEnabled:k(()=>!t.value&&!e.value?!1:s.value?t.value:e.value)}}const $t=71;function ve(s){return typeof s.outline=="object"&&!Array.isArray(s.outline)&&s.outline.label||s.outlineTitle||"On this page"}function pe(s){const e=[...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")].filter(t=>t.id&&t.hasChildNodes()).map(t=>{const n=Number(t.tagName[1]);return{title:kt(t),link:"#"+t.id,level:n}});return yt(e,s)}function kt(s){let e="";for(const t of s.childNodes)if(t.nodeType===1){if(t.classList.contains("VPBadge")||t.classList.contains("header-anchor"))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function yt(s,e){if(e===!1)return[];const t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[n,o]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;s=s.filter(d=>d.level>=n&&d.level<=o);const r=[];e:for(let d=0;d=0;_--){const g=s[_];if(g.level{requestAnimationFrame(r),window.addEventListener("scroll",n)}),Ee(()=>{d(location.hash)}),de(()=>{window.removeEventListener("scroll",n)});function r(){if(!t.value)return;const p=[].slice.call(s.value.querySelectorAll(".outline-link")),_=[].slice.call(document.querySelectorAll(".content .header-anchor")).filter(S=>p.some(C=>C.hash===S.hash&&S.offsetParent!==null)),g=window.scrollY,V=window.innerHeight,y=document.body.offsetHeight,I=Math.abs(g+V-y)<1;if(_.length&&I){d(_[_.length-1].hash);return}for(let S=0;S<_.length;S++){const C=_[S],B=_[S+1],[w,K]=Vt(S,C,B);if(w){d(K);return}}}function d(p){o&&o.classList.remove("active"),p==null?o=null:o=s.value.querySelector(`a[href="${decodeURIComponent(p)}"]`);const _=o;_?(_.classList.add("active"),e.value.style.top=_.offsetTop+33+"px",e.value.style.opacity="1"):(e.value.style.top="33px",e.value.style.opacity="0")}}function ye(s){return s.parentElement.offsetTop-$t}function Vt(s,e,t){const n=window.scrollY;return s===0&&n===0?[!0,null]:n{const o=j("VPDocOutlineItem",!0);return a(),i("ul",{class:T(t.root?"root":"nested")},[(a(!0),i(N,null,A(t.headers,({children:r,link:d,title:p})=>(a(),i("li",null,[c("a",{class:"outline-link",href:d,onClick:e,title:p},L(p),9,wt),r!=null&&r.length?(a(),$(o,{key:0,headers:r},null,8,["headers"])):f("",!0)]))),256))],2)}}});const he=m(Lt,[["__scopeId","data-v-d0ee3533"]]),St=s=>(H("data-v-d330b1bb"),s=s(),z(),s),Mt={class:"content"},Nt={class:"outline-title",role:"heading","aria-level":"2"},It={"aria-labelledby":"doc-outline-aria-label"},Tt=St(()=>c("span",{class:"visually-hidden",id:"doc-outline-aria-label"}," Table of Contents for current page ",-1)),Ct=b({__name:"VPDocAsideOutline",setup(s){const{frontmatter:e,theme:t}=P(),n=_e([]);Y(()=>{n.value=pe(e.value.outline??t.value.outline)});const o=M(),r=M();return Pt(o,r),(d,p)=>(a(),i("div",{class:T(["VPDocAsideOutline",{"has-outline":n.value.length>0}]),ref_key:"container",ref:o,role:"navigation"},[c("div",Mt,[c("div",{class:"outline-marker",ref_key:"marker",ref:r},null,512),c("div",Nt,L(l(ve)(l(t))),1),c("nav",It,[Tt,h(he,{headers:n.value,root:!0},null,8,["headers"])])])],2))}});const Bt=m(Ct,[["__scopeId","data-v-d330b1bb"]]),At={class:"VPDocAsideCarbonAds"},xt=b({__name:"VPDocAsideCarbonAds",props:{carbonAds:{}},setup(s){const e=()=>null;return(t,n)=>(a(),i("div",At,[h(l(e),{"carbon-ads":t.carbonAds},null,8,["carbon-ads"])]))}}),Ht=s=>(H("data-v-3f215769"),s=s(),z(),s),zt={class:"VPDocAside"},Dt=Ht(()=>c("div",{class:"spacer"},null,-1)),Et=b({__name:"VPDocAside",setup(s){const{theme:e}=P();return(t,n)=>(a(),i("div",zt,[u(t.$slots,"aside-top",{},void 0,!0),u(t.$slots,"aside-outline-before",{},void 0,!0),h(Bt),u(t.$slots,"aside-outline-after",{},void 0,!0),Dt,u(t.$slots,"aside-ads-before",{},void 0,!0),l(e).carbonAds?(a(),$(xt,{key:0,"carbon-ads":l(e).carbonAds},null,8,["carbon-ads"])):f("",!0),u(t.$slots,"aside-ads-after",{},void 0,!0),u(t.$slots,"aside-bottom",{},void 0,!0)]))}});const Ft=m(Et,[["__scopeId","data-v-3f215769"]]);function Ot(){const{theme:s,page:e}=P();return k(()=>{const{text:t="Edit this page",pattern:n=""}=s.value.editLink||{};let o;return typeof n=="function"?o=n(e.value):o=n.replace(/:path/g,e.value.filePath),{url:o,text:t}})}function Gt(){const{page:s,theme:e,frontmatter:t}=P();return k(()=>{var _,g,V,y,I,S,C,B;const n=Ne(e.value.sidebar,s.value.relativePath),o=ft(n),r=o.findIndex(w=>O(s.value.relativePath,w.link)),d=((_=e.value.docFooter)==null?void 0:_.prev)===!1&&!t.value.prev||t.value.prev===!1,p=((g=e.value.docFooter)==null?void 0:g.next)===!1&&!t.value.next||t.value.next===!1;return{prev:d?void 0:{text:(typeof t.value.prev=="string"?t.value.prev:typeof t.value.prev=="object"?t.value.prev.text:void 0)??((V=o[r-1])==null?void 0:V.docFooterText)??((y=o[r-1])==null?void 0:y.text),link:(typeof t.value.prev=="object"?t.value.prev.link:void 0)??((I=o[r-1])==null?void 0:I.link)},next:p?void 0:{text:(typeof t.value.next=="string"?t.value.next:typeof t.value.next=="object"?t.value.next.text:void 0)??((S=o[r+1])==null?void 0:S.docFooterText)??((C=o[r+1])==null?void 0:C.text),link:(typeof t.value.next=="object"?t.value.next.link:void 0)??((B=o[r+1])==null?void 0:B.link)}}})}const Ut={},jt={xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},Kt=c("path",{d:"M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"},null,-1),Rt=c("path",{d:"M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"},null,-1),qt=[Kt,Rt];function Wt(s,e){return a(),i("svg",jt,qt)}const Yt=m(Ut,[["render",Wt]]),E=b({__name:"VPLink",props:{tag:{},href:{},noIcon:{type:Boolean},target:{},rel:{}},setup(s){const e=s,t=k(()=>e.tag??(e.href?"a":"span")),n=k(()=>e.href&&we.test(e.href));return(o,r)=>(a(),$(F(t.value),{class:T(["VPLink",{link:o.href,"vp-external-link-icon":n.value,"no-icon":o.noIcon}]),href:o.href?l(J)(o.href):void 0,target:o.target??(n.value?"_blank":void 0),rel:o.rel??(n.value?"noreferrer":void 0)},{default:v(()=>[u(o.$slots,"default")]),_:3},8,["class","href","target","rel"]))}}),Jt={class:"VPLastUpdated"},Xt=["datetime"],Zt=b({__name:"VPDocFooterLastUpdated",setup(s){const{theme:e,page:t,frontmatter:n,lang:o}=P(),r=k(()=>new Date(n.value.lastUpdated??t.value.lastUpdated)),d=k(()=>r.value.toISOString()),p=M("");return G(()=>{te(()=>{var _,g,V;p.value=new Intl.DateTimeFormat((g=(_=e.value.lastUpdated)==null?void 0:_.formatOptions)!=null&&g.forceLocale?o.value:void 0,((V=e.value.lastUpdated)==null?void 0:V.formatOptions)??{dateStyle:"short",timeStyle:"short"}).format(r.value)})}),(_,g)=>{var V;return a(),i("p",Jt,[x(L(((V=l(e).lastUpdated)==null?void 0:V.text)||l(e).lastUpdatedText||"Last updated")+": ",1),c("time",{datetime:d.value},L(p.value),9,Xt)])}}});const Qt=m(Zt,[["__scopeId","data-v-7e05ebdb"]]),es={key:0,class:"VPDocFooter"},ts={key:0,class:"edit-info"},ss={key:0,class:"edit-link"},ns={key:1,class:"last-updated"},os={key:1,class:"prev-next"},as={class:"pager"},rs=["href"],ls=["innerHTML"],is=["innerHTML"],cs={class:"pager"},us=["href"],ds=["innerHTML"],_s=["innerHTML"],vs=b({__name:"VPDocFooter",setup(s){const{theme:e,page:t,frontmatter:n}=P(),o=Ot(),r=Gt(),d=k(()=>e.value.editLink&&n.value.editLink!==!1),p=k(()=>t.value.lastUpdated&&n.value.lastUpdated!==!1),_=k(()=>d.value||p.value||r.value.prev||r.value.next);return(g,V)=>{var y,I,S,C,B,w;return _.value?(a(),i("footer",es,[u(g.$slots,"doc-footer-before",{},void 0,!0),d.value||p.value?(a(),i("div",ts,[d.value?(a(),i("div",ss,[h(E,{class:"edit-link-button",href:l(o).url,"no-icon":!0},{default:v(()=>[h(Yt,{class:"edit-link-icon","aria-label":"edit icon"}),x(" "+L(l(o).text),1)]),_:1},8,["href"])])):f("",!0),p.value?(a(),i("div",ns,[h(Qt)])):f("",!0)])):f("",!0),(y=l(r).prev)!=null&&y.link||(I=l(r).next)!=null&&I.link?(a(),i("nav",os,[c("div",as,[(S=l(r).prev)!=null&&S.link?(a(),i("a",{key:0,class:"pager-link prev",href:l(J)(l(r).prev.link)},[c("span",{class:"desc",innerHTML:((C=l(e).docFooter)==null?void 0:C.prev)||"Previous page"},null,8,ls),c("span",{class:"title",innerHTML:l(r).prev.text},null,8,is)],8,rs)):f("",!0)]),c("div",cs,[(B=l(r).next)!=null&&B.link?(a(),i("a",{key:0,class:"pager-link next",href:l(J)(l(r).next.link)},[c("span",{class:"desc",innerHTML:((w=l(e).docFooter)==null?void 0:w.next)||"Next page"},null,8,ds),c("span",{class:"title",innerHTML:l(r).next.text},null,8,_s)],8,us)):f("",!0)])])):f("",!0)])):f("",!0)}}});const ps=m(vs,[["__scopeId","data-v-ef5dee53"]]),hs={},fs={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},ms=c("path",{d:"M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"},null,-1),gs=[ms];function bs(s,e){return a(),i("svg",fs,gs)}const fe=m(hs,[["render",bs]]),$s={key:0,class:"VPDocOutlineDropdown"},ks={key:0,class:"items"},ys=b({__name:"VPDocOutlineDropdown",setup(s){const{frontmatter:e,theme:t}=P(),n=M(!1);Y(()=>{n.value=!1});const o=_e([]);return Y(()=>{o.value=pe(e.value.outline??t.value.outline)}),(r,d)=>o.value.length>0?(a(),i("div",$s,[c("button",{onClick:d[0]||(d[0]=p=>n.value=!n.value),class:T({open:n.value})},[x(L(l(ve)(l(t)))+" ",1),h(fe,{class:"icon"})],2),n.value?(a(),i("div",ks,[h(he,{headers:o.value},null,8,["headers"])])):f("",!0)])):f("",!0)}});const Ps=m(ys,[["__scopeId","data-v-eadfb36b"]]),Vs=s=>(H("data-v-6b87e69f"),s=s(),z(),s),ws={class:"container"},Ls=Vs(()=>c("div",{class:"aside-curtain"},null,-1)),Ss={class:"aside-container"},Ms={class:"aside-content"},Ns={class:"content"},Is={class:"content-container"},Ts={class:"main"},Cs=b({__name:"VPDoc",setup(s){const{theme:e}=P(),t=se(),{hasSidebar:n,hasAside:o,leftAside:r}=D(),d=k(()=>t.path.replace(/[./]+/g,"_").replace(/_html$/,""));return(p,_)=>{const g=j("Content");return a(),i("div",{class:T(["VPDoc",{"has-sidebar":l(n),"has-aside":l(o)}])},[u(p.$slots,"doc-top",{},void 0,!0),c("div",ws,[l(o)?(a(),i("div",{key:0,class:T(["aside",{"left-aside":l(r)}])},[Ls,c("div",Ss,[c("div",Ms,[h(Ft,null,{"aside-top":v(()=>[u(p.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":v(()=>[u(p.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":v(()=>[u(p.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":v(()=>[u(p.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":v(()=>[u(p.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":v(()=>[u(p.$slots,"aside-ads-after",{},void 0,!0)]),_:3})])])],2)):f("",!0),c("div",Ns,[c("div",Is,[u(p.$slots,"doc-before",{},void 0,!0),h(Ps),c("main",Ts,[h(g,{class:T(["vp-doc",[d.value,l(e).externalLinkIcon&&"external-link-icon-enabled"]])},null,8,["class"])]),h(ps,null,{"doc-footer-before":v(()=>[u(p.$slots,"doc-footer-before",{},void 0,!0)]),_:3}),u(p.$slots,"doc-after",{},void 0,!0)])])]),u(p.$slots,"doc-bottom",{},void 0,!0)],2)}}});const Bs=m(Cs,[["__scopeId","data-v-6b87e69f"]]),As=b({__name:"VPButton",props:{tag:{},size:{default:"medium"},theme:{default:"brand"},text:{},href:{}},setup(s){const e=s,t=k(()=>e.href&&we.test(e.href)),n=k(()=>e.tag||e.href?"a":"button");return(o,r)=>(a(),$(F(n.value),{class:T(["VPButton",[o.size,o.theme]]),href:o.href?l(J)(o.href):void 0,target:t.value?"_blank":void 0,rel:t.value?"noreferrer":void 0},{default:v(()=>[x(L(o.text),1)]),_:1},8,["class","href","target","rel"]))}});const xs=m(As,[["__scopeId","data-v-c1c5efc1"]]),Hs=["src","alt"],zs=b({inheritAttrs:!1,__name:"VPImage",props:{image:{},alt:{}},setup(s){return(e,t)=>{const n=j("VPImage",!0);return e.image?(a(),i(N,{key:0},[typeof e.image=="string"||"src"in e.image?(a(),i("img",Z({key:0,class:"VPImage"},typeof e.image=="string"?e.$attrs:{...e.image,...e.$attrs},{src:l(ue)(typeof e.image=="string"?e.image:e.image.src),alt:e.alt??(typeof e.image=="string"?"":e.image.alt||"")}),null,16,Hs)):(a(),i(N,{key:1},[h(n,Z({class:"dark",image:e.image.dark,alt:e.image.alt},e.$attrs),null,16,["image","alt"]),h(n,Z({class:"light",image:e.image.light,alt:e.image.alt},e.$attrs),null,16,["image","alt"])],64))],64)):f("",!0)}}});const ee=m(zs,[["__scopeId","data-v-8426fc1a"]]),Ds=s=>(H("data-v-da5d1713"),s=s(),z(),s),Es={class:"container"},Fs={class:"main"},Os={key:0,class:"name"},Gs=["innerHTML"],Us=["innerHTML"],js=["innerHTML"],Ks={key:0,class:"actions"},Rs={key:0,class:"image"},qs={class:"image-container"},Ws=Ds(()=>c("div",{class:"image-bg"},null,-1)),Ys=b({__name:"VPHero",props:{name:{},text:{},tagline:{},image:{},actions:{}},setup(s){const e=ne("hero-image-slot-exists");return(t,n)=>(a(),i("div",{class:T(["VPHero",{"has-image":t.image||l(e)}])},[c("div",Es,[c("div",Fs,[u(t.$slots,"home-hero-info",{},()=>[t.name?(a(),i("h1",Os,[c("span",{innerHTML:t.name,class:"clip"},null,8,Gs)])):f("",!0),t.text?(a(),i("p",{key:1,innerHTML:t.text,class:"text"},null,8,Us)):f("",!0),t.tagline?(a(),i("p",{key:2,innerHTML:t.tagline,class:"tagline"},null,8,js)):f("",!0)],!0),t.actions?(a(),i("div",Ks,[(a(!0),i(N,null,A(t.actions,o=>(a(),i("div",{key:o.link,class:"action"},[h(xs,{tag:"a",size:"medium",theme:o.theme,text:o.text,href:o.link},null,8,["theme","text","href"])]))),128))])):f("",!0)]),t.image||l(e)?(a(),i("div",Rs,[c("div",qs,[Ws,u(t.$slots,"home-hero-image",{},()=>[t.image?(a(),$(ee,{key:0,class:"image-src",image:t.image},null,8,["image"])):f("",!0)],!0)])])):f("",!0)])],2))}});const Js=m(Ys,[["__scopeId","data-v-da5d1713"]]),Xs=b({__name:"VPHomeHero",setup(s){const{frontmatter:e}=P();return(t,n)=>l(e).hero?(a(),$(Js,{key:0,class:"VPHomeHero",name:l(e).hero.name,text:l(e).hero.text,tagline:l(e).hero.tagline,image:l(e).hero.image,actions:l(e).hero.actions},{"home-hero-info":v(()=>[u(t.$slots,"home-hero-info")]),"home-hero-image":v(()=>[u(t.$slots,"home-hero-image")]),_:3},8,["name","text","tagline","image","actions"])):f("",!0)}}),Zs={},Qs={xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},en=c("path",{d:"M19.9,12.4c0.1-0.2,0.1-0.5,0-0.8c-0.1-0.1-0.1-0.2-0.2-0.3l-7-7c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l5.3,5.3H5c-0.6,0-1,0.4-1,1s0.4,1,1,1h11.6l-5.3,5.3c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3l7-7C19.8,12.6,19.9,12.5,19.9,12.4z"},null,-1),tn=[en];function sn(s,e){return a(),i("svg",Qs,tn)}const nn=m(Zs,[["render",sn]]),on={class:"box"},an={key:0,class:"icon"},rn=["innerHTML"],ln=["innerHTML"],cn=["innerHTML"],un={key:4,class:"link-text"},dn={class:"link-text-value"},_n=b({__name:"VPFeature",props:{icon:{},title:{},details:{},link:{},linkText:{},rel:{},target:{}},setup(s){return(e,t)=>(a(),$(E,{class:"VPFeature",href:e.link,rel:e.rel,target:e.target,"no-icon":!0,tag:e.link?"a":"div"},{default:v(()=>[c("article",on,[typeof e.icon=="object"&&e.icon.wrap?(a(),i("div",an,[h(ee,{image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])])):typeof e.icon=="object"?(a(),$(ee,{key:1,image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])):e.icon?(a(),i("div",{key:2,class:"icon",innerHTML:e.icon},null,8,rn)):f("",!0),c("h2",{class:"title",innerHTML:e.title},null,8,ln),e.details?(a(),i("p",{key:3,class:"details",innerHTML:e.details},null,8,cn)):f("",!0),e.linkText?(a(),i("div",un,[c("p",dn,[x(L(e.linkText)+" ",1),h(nn,{class:"link-text-icon"})])])):f("",!0)])]),_:1},8,["href","rel","target","tag"]))}});const vn=m(_n,[["__scopeId","data-v-33204567"]]),pn={key:0,class:"VPFeatures"},hn={class:"container"},fn={class:"items"},mn=b({__name:"VPFeatures",props:{features:{}},setup(s){const e=s,t=k(()=>{const n=e.features.length;if(n){if(n===2)return"grid-2";if(n===3)return"grid-3";if(n%3===0)return"grid-6";if(n>3)return"grid-4"}else return});return(n,o)=>n.features?(a(),i("div",pn,[c("div",hn,[c("div",fn,[(a(!0),i(N,null,A(n.features,r=>(a(),i("div",{key:r.title,class:T(["item",[t.value]])},[h(vn,{icon:r.icon,title:r.title,details:r.details,link:r.link,"link-text":r.linkText,rel:r.rel,target:r.target},null,8,["icon","title","details","link","link-text","rel","target"])],2))),128))])])])):f("",!0)}});const gn=m(mn,[["__scopeId","data-v-a6181336"]]),bn=b({__name:"VPHomeFeatures",setup(s){const{frontmatter:e}=P();return(t,n)=>l(e).features?(a(),$(gn,{key:0,class:"VPHomeFeatures",features:l(e).features},null,8,["features"])):f("",!0)}}),$n={class:"VPHome"},kn=b({__name:"VPHome",setup(s){return(e,t)=>{const n=j("Content");return a(),i("div",$n,[u(e.$slots,"home-hero-before",{},void 0,!0),h(Xs,null,{"home-hero-info":v(()=>[u(e.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-image":v(()=>[u(e.$slots,"home-hero-image",{},void 0,!0)]),_:3}),u(e.$slots,"home-hero-after",{},void 0,!0),u(e.$slots,"home-features-before",{},void 0,!0),h(bn),u(e.$slots,"home-features-after",{},void 0,!0),h(n)])}}});const yn=m(kn,[["__scopeId","data-v-d82743a8"]]),Pn={},Vn={class:"VPPage"};function wn(s,e){const t=j("Content");return a(),i("div",Vn,[u(s.$slots,"page-top"),h(t),u(s.$slots,"page-bottom")])}const Ln=m(Pn,[["render",wn]]),Sn=b({__name:"VPContent",setup(s){const{page:e,frontmatter:t}=P(),{hasSidebar:n}=D();return(o,r)=>(a(),i("div",{class:T(["VPContent",{"has-sidebar":l(n),"is-home":l(t).layout==="home"}]),id:"VPContent"},[l(e).isNotFound?u(o.$slots,"not-found",{key:0},()=>[h(pt)],!0):l(t).layout==="page"?(a(),$(Ln,{key:1},{"page-top":v(()=>[u(o.$slots,"page-top",{},void 0,!0)]),"page-bottom":v(()=>[u(o.$slots,"page-bottom",{},void 0,!0)]),_:3})):l(t).layout==="home"?(a(),$(yn,{key:2},{"home-hero-before":v(()=>[u(o.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info":v(()=>[u(o.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-image":v(()=>[u(o.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":v(()=>[u(o.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":v(()=>[u(o.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":v(()=>[u(o.$slots,"home-features-after",{},void 0,!0)]),_:3})):l(t).layout&&l(t).layout!=="doc"?(a(),$(F(l(t).layout),{key:3})):(a(),$(Bs,{key:4},{"doc-top":v(()=>[u(o.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":v(()=>[u(o.$slots,"doc-bottom",{},void 0,!0)]),"doc-footer-before":v(()=>[u(o.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":v(()=>[u(o.$slots,"doc-before",{},void 0,!0)]),"doc-after":v(()=>[u(o.$slots,"doc-after",{},void 0,!0)]),"aside-top":v(()=>[u(o.$slots,"aside-top",{},void 0,!0)]),"aside-outline-before":v(()=>[u(o.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":v(()=>[u(o.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":v(()=>[u(o.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":v(()=>[u(o.$slots,"aside-ads-after",{},void 0,!0)]),"aside-bottom":v(()=>[u(o.$slots,"aside-bottom",{},void 0,!0)]),_:3}))],2))}});const Mn=m(Sn,[["__scopeId","data-v-669faec9"]]),Nn={class:"container"},In=["innerHTML"],Tn=["innerHTML"],Cn=b({__name:"VPFooter",setup(s){const{theme:e,frontmatter:t}=P(),{hasSidebar:n}=D();return(o,r)=>l(e).footer&&l(t).footer!==!1?(a(),i("footer",{key:0,class:T(["VPFooter",{"has-sidebar":l(n)}])},[c("div",Nn,[l(e).footer.message?(a(),i("p",{key:0,class:"message",innerHTML:l(e).footer.message},null,8,In)):f("",!0),l(e).footer.copyright?(a(),i("p",{key:1,class:"copyright",innerHTML:l(e).footer.copyright},null,8,Tn)):f("",!0)])],2)):f("",!0)}});const Bn=m(Cn,[["__scopeId","data-v-e03eb2e1"]]),An={class:"header"},xn={class:"outline"},Hn=b({__name:"VPLocalNavOutlineDropdown",props:{headers:{},navHeight:{}},setup(s){const e=s,{theme:t}=P(),n=M(!1),o=M(0),r=M();Y(()=>{n.value=!1});function d(){n.value=!n.value,o.value=window.innerHeight+Math.min(window.scrollY-e.navHeight,0)}function p(g){g.target.classList.contains("outline-link")&&(r.value&&(r.value.style.transition="none"),Oe(()=>{n.value=!1}))}function _(){n.value=!1,window.scrollTo({top:0,left:0,behavior:"smooth"})}return(g,V)=>(a(),i("div",{class:"VPLocalNavOutlineDropdown",style:Fe({"--vp-vh":o.value+"px"})},[g.headers.length>0?(a(),i("button",{key:0,onClick:d,class:T({open:n.value})},[x(L(l(ve)(l(t)))+" ",1),h(fe,{class:"icon"})],2)):(a(),i("button",{key:1,onClick:_},L(l(t).returnToTopLabel||"Return to top"),1)),h(ce,{name:"flyout"},{default:v(()=>[n.value?(a(),i("div",{key:0,ref_key:"items",ref:r,class:"items",onClick:p},[c("div",An,[c("a",{class:"top-link",href:"#",onClick:_},L(l(t).returnToTopLabel||"Return to top"),1)]),c("div",xn,[h(he,{headers:g.headers},null,8,["headers"])])],512)):f("",!0)]),_:1})],4))}});const zn=m(Hn,[["__scopeId","data-v-1c15a60a"]]),Dn={},En={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},Fn=c("path",{d:"M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"},null,-1),On=c("path",{d:"M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"},null,-1),Gn=c("path",{d:"M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"},null,-1),Un=c("path",{d:"M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"},null,-1),jn=[Fn,On,Gn,Un];function Kn(s,e){return a(),i("svg",En,jn)}const Rn=m(Dn,[["render",Kn]]),qn=["aria-expanded"],Wn={class:"menu-text"},Yn=b({__name:"VPLocalNav",props:{open:{type:Boolean}},emits:["open-menu"],setup(s){const{theme:e,frontmatter:t}=P(),{hasSidebar:n}=D(),{y:o}=Le(),r=_e([]),d=M(0);G(()=>{d.value=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--vp-nav-height"))}),Y(()=>{r.value=pe(t.value.outline??e.value.outline)});const p=k(()=>r.value.length===0&&!n.value),_=k(()=>({VPLocalNav:!0,fixed:p.value,"reached-top":o.value>=d.value}));return(g,V)=>l(t).layout!=="home"&&(!p.value||l(o)>=d.value)?(a(),i("div",{key:0,class:T(_.value)},[l(n)?(a(),i("button",{key:0,class:"menu","aria-expanded":g.open,"aria-controls":"VPSidebarNav",onClick:V[0]||(V[0]=y=>g.$emit("open-menu"))},[h(Rn,{class:"menu-icon"}),c("span",Wn,L(l(e).sidebarMenuLabel||"Menu"),1)],8,qn)):f("",!0),h(zn,{headers:r.value,navHeight:d.value},null,8,["headers","navHeight"])],2)):f("",!0)}});const Jn=m(Yn,[["__scopeId","data-v-79c8c1df"]]);function Xn(){const s=M(!1);function e(){s.value=!0,window.addEventListener("resize",o)}function t(){s.value=!1,window.removeEventListener("resize",o)}function n(){s.value?t():e()}function o(){window.outerWidth>=768&&t()}const r=se();return U(()=>r.path,t),{isScreenOpen:s,openScreen:e,closeScreen:t,toggleScreen:n}}const Zn={},Qn={class:"VPSwitch",type:"button",role:"switch"},eo={class:"check"},to={key:0,class:"icon"};function so(s,e){return a(),i("button",Qn,[c("span",eo,[s.$slots.default?(a(),i("span",to,[u(s.$slots,"default",{},void 0,!0)])):f("",!0)])])}const no=m(Zn,[["render",so],["__scopeId","data-v-b1685198"]]),oo={},ao={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},ro=c("path",{d:"M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"},null,-1),lo=[ro];function io(s,e){return a(),i("svg",ao,lo)}const co=m(oo,[["render",io]]),uo={},_o={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},vo=Ge('',9),po=[vo];function ho(s,e){return a(),i("svg",_o,po)}const fo=m(uo,[["render",ho]]),mo=b({__name:"VPSwitchAppearance",setup(s){const{isDark:e}=P(),t=ne("toggle-appearance",()=>{e.value=!e.value});return(n,o)=>(a(),$(no,{title:"toggle dark mode",class:"VPSwitchAppearance","aria-checked":l(e),onClick:l(t)},{default:v(()=>[h(fo,{class:"sun"}),h(co,{class:"moon"})]),_:1},8,["aria-checked","onClick"]))}});const me=m(mo,[["__scopeId","data-v-ce54a7d1"]]),go={key:0,class:"VPNavBarAppearance"},bo=b({__name:"VPNavBarAppearance",setup(s){const{site:e}=P();return(t,n)=>l(e).appearance&&l(e).appearance!=="force-dark"?(a(),i("div",go,[h(me)])):f("",!0)}});const $o=m(bo,[["__scopeId","data-v-e6aabb21"]]),ge=M();let Te=!1,ae=0;function ko(s){const e=M(!1);if(q){!Te&&yo(),ae++;const t=U(ge,n=>{var o,r,d;n===s.el.value||(o=s.el.value)!=null&&o.contains(n)?(e.value=!0,(r=s.onFocus)==null||r.call(s)):(e.value=!1,(d=s.onBlur)==null||d.call(s))});de(()=>{t(),ae--,ae||Po()})}return Ue(e)}function yo(){document.addEventListener("focusin",Ce),Te=!0,ge.value=document.activeElement}function Po(){document.removeEventListener("focusin",Ce)}function Ce(){ge.value=document.activeElement}const Vo={},wo={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},Lo=c("path",{d:"M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"},null,-1),So=[Lo];function Mo(s,e){return a(),i("svg",wo,So)}const Be=m(Vo,[["render",Mo]]),No={},Io={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},To=c("circle",{cx:"12",cy:"12",r:"2"},null,-1),Co=c("circle",{cx:"19",cy:"12",r:"2"},null,-1),Bo=c("circle",{cx:"5",cy:"12",r:"2"},null,-1),Ao=[To,Co,Bo];function xo(s,e){return a(),i("svg",Io,Ao)}const Ho=m(No,[["render",xo]]),zo={class:"VPMenuLink"},Do=b({__name:"VPMenuLink",props:{item:{}},setup(s){const{page:e}=P();return(t,n)=>(a(),i("div",zo,[h(E,{class:T({active:l(O)(l(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel},{default:v(()=>[x(L(t.item.text),1)]),_:1},8,["class","href","target","rel"])]))}});const oe=m(Do,[["__scopeId","data-v-43f1e123"]]),Eo={class:"VPMenuGroup"},Fo={key:0,class:"title"},Oo=b({__name:"VPMenuGroup",props:{text:{},items:{}},setup(s){return(e,t)=>(a(),i("div",Eo,[e.text?(a(),i("p",Fo,L(e.text),1)):f("",!0),(a(!0),i(N,null,A(e.items,n=>(a(),i(N,null,["link"in n?(a(),$(oe,{key:0,item:n},null,8,["item"])):f("",!0)],64))),256))]))}});const Go=m(Oo,[["__scopeId","data-v-69e747b5"]]),Uo={class:"VPMenu"},jo={key:0,class:"items"},Ko=b({__name:"VPMenu",props:{items:{}},setup(s){return(e,t)=>(a(),i("div",Uo,[e.items?(a(),i("div",jo,[(a(!0),i(N,null,A(e.items,n=>(a(),i(N,{key:n.text},["link"in n?(a(),$(oe,{key:0,item:n},null,8,["item"])):(a(),$(Go,{key:1,text:n.text,items:n.items},null,8,["text","items"]))],64))),128))])):f("",!0),u(e.$slots,"default",{},void 0,!0)]))}});const Ro=m(Ko,[["__scopeId","data-v-e7ea1737"]]),qo=["aria-expanded","aria-label"],Wo={key:0,class:"text"},Yo=["innerHTML"],Jo={class:"menu"},Xo=b({__name:"VPFlyout",props:{icon:{},button:{},label:{},items:{}},setup(s){const e=M(!1),t=M();ko({el:t,onBlur:n});function n(){e.value=!1}return(o,r)=>(a(),i("div",{class:"VPFlyout",ref_key:"el",ref:t,onMouseenter:r[1]||(r[1]=d=>e.value=!0),onMouseleave:r[2]||(r[2]=d=>e.value=!1)},[c("button",{type:"button",class:"button","aria-haspopup":"true","aria-expanded":e.value,"aria-label":o.label,onClick:r[0]||(r[0]=d=>e.value=!e.value)},[o.button||o.icon?(a(),i("span",Wo,[o.icon?(a(),$(F(o.icon),{key:0,class:"option-icon"})):f("",!0),o.button?(a(),i("span",{key:1,innerHTML:o.button},null,8,Yo)):f("",!0),h(Be,{class:"text-icon"})])):(a(),$(Ho,{key:1,class:"icon"}))],8,qo),c("div",Jo,[h(Ro,{items:o.items},{default:v(()=>[u(o.$slots,"default",{},void 0,!0)]),_:3},8,["items"])])],544))}});const be=m(Xo,[["__scopeId","data-v-9c007e85"]]),Zo={discord:'Discord',facebook:'Facebook',github:'GitHub',instagram:'Instagram',linkedin:'LinkedIn',mastodon:'Mastodon',slack:'Slack',twitter:'Twitter',x:'X',youtube:'YouTube'},Qo=["href","aria-label","innerHTML"],ea=b({__name:"VPSocialLink",props:{icon:{},link:{},ariaLabel:{}},setup(s){const e=s,t=k(()=>typeof e.icon=="object"?e.icon.svg:Zo[e.icon]);return(n,o)=>(a(),i("a",{class:"VPSocialLink no-icon",href:n.link,"aria-label":n.ariaLabel??(typeof n.icon=="string"?n.icon:""),target:"_blank",rel:"noopener",innerHTML:t.value},null,8,Qo))}});const ta=m(ea,[["__scopeId","data-v-f80f8133"]]),sa={class:"VPSocialLinks"},na=b({__name:"VPSocialLinks",props:{links:{}},setup(s){return(e,t)=>(a(),i("div",sa,[(a(!0),i(N,null,A(e.links,({link:n,icon:o,ariaLabel:r})=>(a(),$(ta,{key:n,icon:o,link:n,ariaLabel:r},null,8,["icon","link","ariaLabel"]))),128))]))}});const $e=m(na,[["__scopeId","data-v-7bc22406"]]),oa={key:0,class:"group translations"},aa={class:"trans-title"},ra={key:1,class:"group"},la={class:"item appearance"},ia={class:"label"},ca={class:"appearance-action"},ua={key:2,class:"group"},da={class:"item social-links"},_a=b({__name:"VPNavBarExtra",setup(s){const{site:e,theme:t}=P(),{localeLinks:n,currentLang:o}=X({correspondingLink:!0}),r=k(()=>n.value.length&&o.value.label||e.value.appearance||t.value.socialLinks);return(d,p)=>r.value?(a(),$(be,{key:0,class:"VPNavBarExtra",label:"extra navigation"},{default:v(()=>[l(n).length&&l(o).label?(a(),i("div",oa,[c("p",aa,L(l(o).label),1),(a(!0),i(N,null,A(l(n),_=>(a(),$(oe,{key:_.link,item:_},null,8,["item"]))),128))])):f("",!0),l(e).appearance?(a(),i("div",ra,[c("div",la,[c("p",ia,L(l(t).darkModeSwitchLabel||"Appearance"),1),c("div",ca,[h(me)])])])):f("",!0),l(t).socialLinks?(a(),i("div",ua,[c("div",da,[h($e,{class:"social-links-list",links:l(t).socialLinks},null,8,["links"])])])):f("",!0)]),_:1})):f("",!0)}});const va=m(_a,[["__scopeId","data-v-40855f84"]]),pa=s=>(H("data-v-e5dd9c1c"),s=s(),z(),s),ha=["aria-expanded"],fa=pa(()=>c("span",{class:"container"},[c("span",{class:"top"}),c("span",{class:"middle"}),c("span",{class:"bottom"})],-1)),ma=[fa],ga=b({__name:"VPNavBarHamburger",props:{active:{type:Boolean}},emits:["click"],setup(s){return(e,t)=>(a(),i("button",{type:"button",class:T(["VPNavBarHamburger",{active:e.active}]),"aria-label":"mobile navigation","aria-expanded":e.active,"aria-controls":"VPNavScreen",onClick:t[0]||(t[0]=n=>e.$emit("click"))},ma,10,ha))}});const ba=m(ga,[["__scopeId","data-v-e5dd9c1c"]]),$a=["innerHTML"],ka=b({__name:"VPNavBarMenuLink",props:{item:{}},setup(s){const{page:e}=P();return(t,n)=>(a(),$(E,{class:T({VPNavBarMenuLink:!0,active:l(O)(l(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,tabindex:"0"},{default:v(()=>[c("span",{innerHTML:t.item.text},null,8,$a)]),_:1},8,["class","href","target","rel"]))}});const ya=m(ka,[["__scopeId","data-v-42ef59de"]]),Pa=b({__name:"VPNavBarMenuGroup",props:{item:{}},setup(s){const e=s,{page:t}=P(),n=r=>"link"in r?O(t.value.relativePath,r.link,!!e.item.activeMatch):r.items.some(n),o=k(()=>n(e.item));return(r,d)=>(a(),$(be,{class:T({VPNavBarMenuGroup:!0,active:l(O)(l(t).relativePath,r.item.activeMatch,!!r.item.activeMatch)||o.value}),button:r.item.text,items:r.item.items},null,8,["class","button","items"]))}}),Va=s=>(H("data-v-7f418b0f"),s=s(),z(),s),wa={key:0,"aria-labelledby":"main-nav-aria-label",class:"VPNavBarMenu"},La=Va(()=>c("span",{id:"main-nav-aria-label",class:"visually-hidden"},"Main Navigation",-1)),Sa=b({__name:"VPNavBarMenu",setup(s){const{theme:e}=P();return(t,n)=>l(e).nav?(a(),i("nav",wa,[La,(a(!0),i(N,null,A(l(e).nav,o=>(a(),i(N,{key:o.text},["link"in o?(a(),$(ya,{key:0,item:o},null,8,["item"])):(a(),$(Pa,{key:1,item:o},null,8,["item"]))],64))),128))])):f("",!0)}});const Ma=m(Sa,[["__scopeId","data-v-7f418b0f"]]);function Na(s,e){const{localeIndex:t}=P();function n(o){var S,C;const r=o.split("."),d=s&&typeof s=="object",p=d&&((C=(S=s.locales)==null?void 0:S[t.value])==null?void 0:C.translations)||null,_=d&&s.translations||null;let g=p,V=_,y=e;const I=r.pop();for(const B of r){let w=null;const K=y==null?void 0:y[B];K&&(w=y=K);const W=V==null?void 0:V[B];W&&(w=V=W);const R=g==null?void 0:g[B];R&&(w=g=R),K||(y=w),W||(V=w),R||(g=w)}return(g==null?void 0:g[I])??(V==null?void 0:V[I])??(y==null?void 0:y[I])??""}return n}const Ia=["aria-label"],Ta={class:"DocSearch-Button-Container"},Ca=c("svg",{class:"DocSearch-Search-Icon",width:"20",height:"20",viewBox:"0 0 20 20","aria-label":"search icon"},[c("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none","fill-rule":"evenodd","stroke-linecap":"round","stroke-linejoin":"round"})],-1),Ba={class:"DocSearch-Button-Placeholder"},Aa=c("span",{class:"DocSearch-Button-Keys"},[c("kbd",{class:"DocSearch-Button-Key"}),c("kbd",{class:"DocSearch-Button-Key"},"K")],-1),Pe=b({__name:"VPNavBarSearchButton",setup(s){const{theme:e}=P(),t={button:{buttonText:"Search",buttonAriaLabel:"Search"}},n=je(Na)(Ke(()=>{var o;return(o=e.value.search)==null?void 0:o.options}),t);return(o,r)=>(a(),i("button",{type:"button",class:"DocSearch DocSearch-Button","aria-label":l(n)("button.buttonAriaLabel")},[c("span",Ta,[Ca,c("span",Ba,L(l(n)("button.buttonText")),1)]),Aa],8,Ia))}});const xa={class:"VPNavBarSearch"},Ha={id:"local-search"},za={key:1,id:"docsearch"},Da=b({__name:"VPNavBarSearch",setup(s){const e=Re(()=>qe(()=>import("./VPLocalSearchBox.0bede1e4.js"),["assets/chunks/VPLocalSearchBox.0bede1e4.js","assets/chunks/framework.c53372a0.js"])),t=()=>null,{theme:n}=P(),o=M(!1),r=M(!1);G(()=>{});function d(){o.value||(o.value=!0,setTimeout(p,16))}function p(){const y=new Event("keydown");y.key="k",y.metaKey=!0,window.dispatchEvent(y),setTimeout(()=>{document.querySelector(".DocSearch-Modal")||p()},16)}function _(y){const I=y.target,S=I.tagName;return I.isContentEditable||S==="INPUT"||S==="SELECT"||S==="TEXTAREA"}const g=M(!1);ke("k",y=>{(y.ctrlKey||y.metaKey)&&(y.preventDefault(),g.value=!0)}),ke("/",y=>{_(y)||(y.preventDefault(),g.value=!0)});const V="local";return(y,I)=>{var S;return a(),i("div",xa,[l(V)==="local"?(a(),i(N,{key:0},[g.value?(a(),$(l(e),{key:0,onClose:I[0]||(I[0]=C=>g.value=!1)})):f("",!0),c("div",Ha,[h(Pe,{onClick:I[1]||(I[1]=C=>g.value=!0)})])],64)):l(V)==="algolia"?(a(),i(N,{key:1},[o.value?(a(),$(l(t),{key:0,algolia:((S=l(n).search)==null?void 0:S.options)??l(n).algolia,onVnodeBeforeMount:I[2]||(I[2]=C=>r.value=!0)},null,8,["algolia"])):f("",!0),r.value?f("",!0):(a(),i("div",za,[h(Pe,{onClick:d})]))],64)):f("",!0)])}}});const Ea=b({__name:"VPNavBarSocialLinks",setup(s){const{theme:e}=P();return(t,n)=>l(e).socialLinks?(a(),$($e,{key:0,class:"VPNavBarSocialLinks",links:l(e).socialLinks},null,8,["links"])):f("",!0)}});const Fa=m(Ea,[["__scopeId","data-v-0394ad82"]]),Oa=["href"],Ga=b({__name:"VPNavBarTitle",setup(s){const{site:e,theme:t}=P(),{hasSidebar:n}=D(),{currentLang:o}=X();return(r,d)=>(a(),i("div",{class:T(["VPNavBarTitle",{"has-sidebar":l(n)}])},[c("a",{class:"title",href:l(t).logoLink??l(J)(l(o).link)},[u(r.$slots,"nav-bar-title-before",{},void 0,!0),l(t).logo?(a(),$(ee,{key:0,class:"logo",image:l(t).logo},null,8,["image"])):f("",!0),l(t).siteTitle?(a(),i(N,{key:1},[x(L(l(t).siteTitle),1)],64)):l(t).siteTitle===void 0?(a(),i(N,{key:2},[x(L(l(e).title),1)],64)):f("",!0),u(r.$slots,"nav-bar-title-after",{},void 0,!0)],8,Oa)],2))}});const Ua=m(Ga,[["__scopeId","data-v-86d1bed8"]]),ja={},Ka={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},Ra=c("path",{d:"M0 0h24v24H0z",fill:"none"},null,-1),qa=c("path",{d:" M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z ",class:"css-c4d79v"},null,-1),Wa=[Ra,qa];function Ya(s,e){return a(),i("svg",Ka,Wa)}const Ae=m(ja,[["render",Ya]]),Ja={class:"items"},Xa={class:"title"},Za=b({__name:"VPNavBarTranslations",setup(s){const{theme:e}=P(),{localeLinks:t,currentLang:n}=X({correspondingLink:!0});return(o,r)=>l(t).length&&l(n).label?(a(),$(be,{key:0,class:"VPNavBarTranslations",icon:Ae,label:l(e).langMenuLabel||"Change language"},{default:v(()=>[c("div",Ja,[c("p",Xa,L(l(n).label),1),(a(!0),i(N,null,A(l(t),d=>(a(),$(oe,{key:d.link,item:d},null,8,["item"]))),128))])]),_:1},8,["label"])):f("",!0)}});const Qa=m(Za,[["__scopeId","data-v-74abcbb9"]]),er=s=>(H("data-v-a0fd61f4"),s=s(),z(),s),tr={class:"container"},sr={class:"title"},nr={class:"content"},or=er(()=>c("div",{class:"curtain"},null,-1)),ar={class:"content-body"},rr=b({__name:"VPNavBar",props:{isScreenOpen:{type:Boolean}},emits:["toggle-screen"],setup(s){const{y:e}=Le(),{hasSidebar:t}=D(),{frontmatter:n}=P(),o=M({});return Ve(()=>{o.value={"has-sidebar":t.value,top:n.value.layout==="home"&&e.value===0}}),(r,d)=>(a(),i("div",{class:T(["VPNavBar",o.value])},[c("div",tr,[c("div",sr,[h(Ua,null,{"nav-bar-title-before":v(()=>[u(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":v(()=>[u(r.$slots,"nav-bar-title-after",{},void 0,!0)]),_:3})]),c("div",nr,[or,c("div",ar,[u(r.$slots,"nav-bar-content-before",{},void 0,!0),h(Da,{class:"search"}),h(Ma,{class:"menu"}),h(Qa,{class:"translations"}),h($o,{class:"appearance"}),h(Fa,{class:"social-links"}),h(va,{class:"extra"}),u(r.$slots,"nav-bar-content-after",{},void 0,!0),h(ba,{class:"hamburger",active:r.isScreenOpen,onClick:d[0]||(d[0]=p=>r.$emit("toggle-screen"))},null,8,["active"])])])])],2))}});const lr=m(rr,[["__scopeId","data-v-a0fd61f4"]]),ir={key:0,class:"VPNavScreenAppearance"},cr={class:"text"},ur=b({__name:"VPNavScreenAppearance",setup(s){const{site:e,theme:t}=P();return(n,o)=>l(e).appearance?(a(),i("div",ir,[c("p",cr,L(l(t).darkModeSwitchLabel||"Appearance"),1),h(me)])):f("",!0)}});const dr=m(ur,[["__scopeId","data-v-add8f686"]]),_r=b({__name:"VPNavScreenMenuLink",props:{item:{}},setup(s){const e=ne("close-screen");return(t,n)=>(a(),$(E,{class:"VPNavScreenMenuLink",href:t.item.link,target:t.item.target,rel:t.item.rel,onClick:l(e)},{default:v(()=>[x(L(t.item.text),1)]),_:1},8,["href","target","rel","onClick"]))}});const vr=m(_r,[["__scopeId","data-v-05f27b2a"]]),pr={},hr={xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",viewBox:"0 0 24 24"},fr=c("path",{d:"M18.9,10.9h-6v-6c0-0.6-0.4-1-1-1s-1,0.4-1,1v6h-6c-0.6,0-1,0.4-1,1s0.4,1,1,1h6v6c0,0.6,0.4,1,1,1s1-0.4,1-1v-6h6c0.6,0,1-0.4,1-1S19.5,10.9,18.9,10.9z"},null,-1),mr=[fr];function gr(s,e){return a(),i("svg",hr,mr)}const br=m(pr,[["render",gr]]),$r=b({__name:"VPNavScreenMenuGroupLink",props:{item:{}},setup(s){const e=ne("close-screen");return(t,n)=>(a(),$(E,{class:"VPNavScreenMenuGroupLink",href:t.item.link,target:t.item.target,rel:t.item.rel,onClick:l(e)},{default:v(()=>[x(L(t.item.text),1)]),_:1},8,["href","target","rel","onClick"]))}});const xe=m($r,[["__scopeId","data-v-19976ae1"]]),kr={class:"VPNavScreenMenuGroupSection"},yr={key:0,class:"title"},Pr=b({__name:"VPNavScreenMenuGroupSection",props:{text:{},items:{}},setup(s){return(e,t)=>(a(),i("div",kr,[e.text?(a(),i("p",yr,L(e.text),1)):f("",!0),(a(!0),i(N,null,A(e.items,n=>(a(),$(xe,{key:n.text,item:n},null,8,["item"]))),128))]))}});const Vr=m(Pr,[["__scopeId","data-v-8133b170"]]),wr=["aria-controls","aria-expanded"],Lr={class:"button-text"},Sr=["id"],Mr={key:1,class:"group"},Nr=b({__name:"VPNavScreenMenuGroup",props:{text:{},items:{}},setup(s){const e=s,t=M(!1),n=k(()=>`NavScreenGroup-${e.text.replace(" ","-").toLowerCase()}`);function o(){t.value=!t.value}return(r,d)=>(a(),i("div",{class:T(["VPNavScreenMenuGroup",{open:t.value}])},[c("button",{class:"button","aria-controls":n.value,"aria-expanded":t.value,onClick:o},[c("span",Lr,L(r.text),1),h(br,{class:"button-icon"})],8,wr),c("div",{id:n.value,class:"items"},[(a(!0),i(N,null,A(r.items,p=>(a(),i(N,{key:p.text},["link"in p?(a(),i("div",{key:p.text,class:"item"},[h(xe,{item:p},null,8,["item"])])):(a(),i("div",Mr,[h(Vr,{text:p.text,items:p.items},null,8,["text","items"])]))],64))),128))],8,Sr)],2))}});const Ir=m(Nr,[["__scopeId","data-v-1ecb84e7"]]),Tr={key:0,class:"VPNavScreenMenu"},Cr=b({__name:"VPNavScreenMenu",setup(s){const{theme:e}=P();return(t,n)=>l(e).nav?(a(),i("nav",Tr,[(a(!0),i(N,null,A(l(e).nav,o=>(a(),i(N,{key:o.text},["link"in o?(a(),$(vr,{key:0,item:o},null,8,["item"])):(a(),$(Ir,{key:1,text:o.text||"",items:o.items},null,8,["text","items"]))],64))),128))])):f("",!0)}}),Br=b({__name:"VPNavScreenSocialLinks",setup(s){const{theme:e}=P();return(t,n)=>l(e).socialLinks?(a(),$($e,{key:0,class:"VPNavScreenSocialLinks",links:l(e).socialLinks},null,8,["links"])):f("",!0)}}),Ar={class:"list"},xr=b({__name:"VPNavScreenTranslations",setup(s){const{localeLinks:e,currentLang:t}=X({correspondingLink:!0}),n=M(!1);function o(){n.value=!n.value}return(r,d)=>l(e).length&&l(t).label?(a(),i("div",{key:0,class:T(["VPNavScreenTranslations",{open:n.value}])},[c("button",{class:"title",onClick:o},[h(Ae,{class:"icon lang"}),x(" "+L(l(t).label)+" ",1),h(Be,{class:"icon chevron"})]),c("ul",Ar,[(a(!0),i(N,null,A(l(e),p=>(a(),i("li",{key:p.link,class:"item"},[h(E,{class:"link",href:p.link},{default:v(()=>[x(L(p.text),1)]),_:2},1032,["href"])]))),128))])],2)):f("",!0)}});const Hr=m(xr,[["__scopeId","data-v-d72aa483"]]),zr={class:"container"},Dr=b({__name:"VPNavScreen",props:{open:{type:Boolean}},setup(s){const e=M(null),t=Se(q?document.body:null);return(n,o)=>(a(),$(ce,{name:"fade",onEnter:o[0]||(o[0]=r=>t.value=!0),onAfterLeave:o[1]||(o[1]=r=>t.value=!1)},{default:v(()=>[n.open?(a(),i("div",{key:0,class:"VPNavScreen",ref_key:"screen",ref:e,id:"VPNavScreen"},[c("div",zr,[u(n.$slots,"nav-screen-content-before",{},void 0,!0),h(Cr,{class:"menu"}),h(Hr,{class:"translations"}),h(dr,{class:"appearance"}),h(Br,{class:"social-links"}),u(n.$slots,"nav-screen-content-after",{},void 0,!0)])],512)):f("",!0)]),_:3}))}});const Er=m(Dr,[["__scopeId","data-v-cc5739dd"]]),Fr={key:0,class:"VPNav"},Or=b({__name:"VPNav",setup(s){const{isScreenOpen:e,closeScreen:t,toggleScreen:n}=Xn(),{frontmatter:o}=P(),r=k(()=>o.value.navbar!==!1);return Me("close-screen",t),te(()=>{q&&document.documentElement.classList.toggle("hide-nav",!r.value)}),(d,p)=>r.value?(a(),i("header",Fr,[h(lr,{"is-screen-open":l(e),onToggleScreen:l(n)},{"nav-bar-title-before":v(()=>[u(d.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":v(()=>[u(d.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":v(()=>[u(d.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":v(()=>[u(d.$slots,"nav-bar-content-after",{},void 0,!0)]),_:3},8,["is-screen-open","onToggleScreen"]),h(Er,{open:l(e)},{"nav-screen-content-before":v(()=>[u(d.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":v(()=>[u(d.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3},8,["open"])])):f("",!0)}});const Gr=m(Or,[["__scopeId","data-v-ae24b3ad"]]),Ur=s=>(H("data-v-e31bd47b"),s=s(),z(),s),jr=["role","tabindex"],Kr=Ur(()=>c("div",{class:"indicator"},null,-1)),Rr=["onKeydown"],qr={key:1,class:"items"},Wr=b({__name:"VPSidebarItem",props:{item:{},depth:{}},setup(s){const e=s,{collapsed:t,collapsible:n,isLink:o,isActiveLink:r,hasActiveLink:d,hasChildren:p,toggle:_}=gt(k(()=>e.item)),g=k(()=>p.value?"section":"div"),V=k(()=>o.value?"a":"div"),y=k(()=>p.value?e.depth+2===7?"p":`h${e.depth+2}`:"p"),I=k(()=>o.value?void 0:"button"),S=k(()=>[[`level-${e.depth}`],{collapsible:n.value},{collapsed:t.value},{"is-link":o.value},{"is-active":r.value},{"has-active":d.value}]);function C(w){"key"in w&&w.key!=="Enter"||!e.item.link&&_()}function B(){e.item.link&&_()}return(w,K)=>{const W=j("VPSidebarItem",!0);return a(),$(F(g.value),{class:T(["VPSidebarItem",S.value])},{default:v(()=>[w.item.text?(a(),i("div",Z({key:0,class:"item",role:I.value},We(w.item.items?{click:C,keydown:C}:{},!0),{tabindex:w.item.items&&0}),[Kr,w.item.link?(a(),$(E,{key:0,tag:V.value,class:"link",href:w.item.link,rel:w.item.rel,target:w.item.target},{default:v(()=>[(a(),$(F(y.value),{class:"text",innerHTML:w.item.text},null,8,["innerHTML"]))]),_:1},8,["tag","href","rel","target"])):(a(),$(F(y.value),{key:1,class:"text",innerHTML:w.item.text},null,8,["innerHTML"])),w.item.collapsed!=null?(a(),i("div",{key:2,class:"caret",role:"button","aria-label":"toggle section",onClick:B,onKeydown:Ye(B,["enter"]),tabindex:"0"},[h(fe,{class:"caret-icon"})],40,Rr)):f("",!0)],16,jr)):f("",!0),w.item.items&&w.item.items.length?(a(),i("div",qr,[w.depth<5?(a(!0),i(N,{key:0},A(w.item.items,R=>(a(),$(W,{key:R.text,item:R,depth:w.depth+1},null,8,["item","depth"]))),128)):f("",!0)])):f("",!0)]),_:1},8,["class"])}}});const Yr=m(Wr,[["__scopeId","data-v-e31bd47b"]]),He=s=>(H("data-v-b00e2fdd"),s=s(),z(),s),Jr=He(()=>c("div",{class:"curtain"},null,-1)),Xr={class:"nav",id:"VPSidebarNav","aria-labelledby":"sidebar-aria-label",tabindex:"-1"},Zr=He(()=>c("span",{class:"visually-hidden",id:"sidebar-aria-label"}," Sidebar Navigation ",-1)),Qr=b({__name:"VPSidebar",props:{open:{type:Boolean}},setup(s){const{sidebarGroups:e,hasSidebar:t}=D(),n=s,o=M(null),r=Se(q?document.body:null);return U([n,o],()=>{var d;n.open?(r.value=!0,(d=o.value)==null||d.focus()):r.value=!1},{immediate:!0,flush:"post"}),(d,p)=>l(t)?(a(),i("aside",{key:0,class:T(["VPSidebar",{open:d.open}]),ref_key:"navEl",ref:o,onClick:p[0]||(p[0]=Je(()=>{},["stop"]))},[Jr,c("nav",Xr,[Zr,u(d.$slots,"sidebar-nav-before",{},void 0,!0),(a(!0),i(N,null,A(l(e),_=>(a(),i("div",{key:_.text,class:"group"},[h(Yr,{item:_,depth:0},null,8,["item"])]))),128)),u(d.$slots,"sidebar-nav-after",{},void 0,!0)])],2)):f("",!0)}});const el=m(Qr,[["__scopeId","data-v-b00e2fdd"]]),tl=b({__name:"VPSkipLink",setup(s){const e=se(),t=M();U(()=>e.path,()=>t.value.focus());function n({target:o}){const r=document.getElementById(decodeURIComponent(o.hash).slice(1));if(r){const d=()=>{r.removeAttribute("tabindex"),r.removeEventListener("blur",d)};r.setAttribute("tabindex","-1"),r.addEventListener("blur",d),r.focus(),window.scrollTo(0,0)}}return(o,r)=>(a(),i(N,null,[c("span",{ref_key:"backToTop",ref:t,tabindex:"-1"},null,512),c("a",{href:"#VPContent",class:"VPSkipLink visually-hidden",onClick:n}," Skip to content ")],64))}});const sl=m(tl,[["__scopeId","data-v-0f60ec36"]]),nl=b({__name:"Layout",setup(s){const{isOpen:e,open:t,close:n}=D(),o=se();U(()=>o.path,n),mt(e,n);const{frontmatter:r}=P(),d=Xe(),p=k(()=>!!d["home-hero-image"]);return Me("hero-image-slot-exists",p),(_,g)=>{const V=j("Content");return l(r).layout!==!1?(a(),i("div",{key:0,class:T(["Layout",l(r).pageClass])},[u(_.$slots,"layout-top",{},void 0,!0),h(sl),h(st,{class:"backdrop",show:l(e),onClick:l(n)},null,8,["show","onClick"]),h(Gr,null,{"nav-bar-title-before":v(()=>[u(_.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":v(()=>[u(_.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":v(()=>[u(_.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":v(()=>[u(_.$slots,"nav-bar-content-after",{},void 0,!0)]),"nav-screen-content-before":v(()=>[u(_.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":v(()=>[u(_.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3}),h(Jn,{open:l(e),onOpenMenu:l(t)},null,8,["open","onOpenMenu"]),h(el,{open:l(e)},{"sidebar-nav-before":v(()=>[u(_.$slots,"sidebar-nav-before",{},void 0,!0)]),"sidebar-nav-after":v(()=>[u(_.$slots,"sidebar-nav-after",{},void 0,!0)]),_:3},8,["open"]),h(Mn,null,{"page-top":v(()=>[u(_.$slots,"page-top",{},void 0,!0)]),"page-bottom":v(()=>[u(_.$slots,"page-bottom",{},void 0,!0)]),"not-found":v(()=>[u(_.$slots,"not-found",{},void 0,!0)]),"home-hero-before":v(()=>[u(_.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info":v(()=>[u(_.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-image":v(()=>[u(_.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":v(()=>[u(_.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":v(()=>[u(_.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":v(()=>[u(_.$slots,"home-features-after",{},void 0,!0)]),"doc-footer-before":v(()=>[u(_.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":v(()=>[u(_.$slots,"doc-before",{},void 0,!0)]),"doc-after":v(()=>[u(_.$slots,"doc-after",{},void 0,!0)]),"doc-top":v(()=>[u(_.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":v(()=>[u(_.$slots,"doc-bottom",{},void 0,!0)]),"aside-top":v(()=>[u(_.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":v(()=>[u(_.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":v(()=>[u(_.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":v(()=>[u(_.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":v(()=>[u(_.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":v(()=>[u(_.$slots,"aside-ads-after",{},void 0,!0)]),_:3}),h(Bn),u(_.$slots,"layout-bottom",{},void 0,!0)],2)):(a(),$(V,{key:1}))}}});const ol=m(nl,[["__scopeId","data-v-5a346dfe"]]);const rl={Layout:ol,enhanceApp:({app:s})=>{s.component("Badge",Qe)}};export{Na as c,rl as t,P as u}; diff --git a/assets/index.md.4cc1630f.js b/assets/index.md.4cc1630f.js new file mode 100644 index 00000000..073b8da6 --- /dev/null +++ b/assets/index.md.4cc1630f.js @@ -0,0 +1 @@ +import{_ as t,o as e,c as i}from"./chunks/framework.c53372a0.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"ZerDocs","text":"VitePress Front-End Learning Collection","image":{"src":"https://zerdocs.oss-cn-shanghai.aliyuncs.com/202302041807975.svg","alt":"ZerDocs"},"actions":[{"theme":"brand","text":"开始阅读","link":"/FrontEnd/Git/Terminal终端美化"},{"theme":"alt","text":"关于我","link":"https://github.com/fxzer"}]},"features":[{"icon":"🎨","title":"FrontEnd","details":"前端三件套相关基础积累。","link":"/FrontEnd/Git/Terminal终端美化"},{"icon":"🚚","title":"Framework","details":"总结前段框架学习笔记。","link":"/Framework/Vue/列表最后一条数据删除处理"},{"icon":"📝","title":"Problem","details":"积累编程中遇到的坑。","link":"/Problem/"},{"icon":"🧑‍💻","title":"Interview","details":"归纳前端经典面试题。","link":"/Interview/"},{"icon":"🔐","title":"TypeScript","details":"TypeScript 中英文档","link":"https://fxzer.github.io/tsdoc-vitepress/zh/"},{"icon":"🔐","title":"TypeScript","details":"TypeScript 教程","link":"https://fxzer.github.io/typescript-tutorial-vitepress/"},{"icon":"💫","title":"Canvas","details":"有趣的 Canvas 练习","link":"https://fxzer.github.io/funny-canvas/#/a"},{"icon":"🤡","title":"Tailwind CSS","details":"Tailwind CSS 案例练习","link":"https://fxzer.github.io/tailwindcss-showcase/#/"}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function a(s,r,o,l,c,d){return e(),i("div")}const m=t(n,[["render",a]]);export{h as __pageData,m as default}; diff --git a/assets/index.md.4cc1630f.lean.js b/assets/index.md.4cc1630f.lean.js new file mode 100644 index 00000000..073b8da6 --- /dev/null +++ b/assets/index.md.4cc1630f.lean.js @@ -0,0 +1 @@ +import{_ as t,o as e,c as i}from"./chunks/framework.c53372a0.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"home","hero":{"name":"ZerDocs","text":"VitePress Front-End Learning Collection","image":{"src":"https://zerdocs.oss-cn-shanghai.aliyuncs.com/202302041807975.svg","alt":"ZerDocs"},"actions":[{"theme":"brand","text":"开始阅读","link":"/FrontEnd/Git/Terminal终端美化"},{"theme":"alt","text":"关于我","link":"https://github.com/fxzer"}]},"features":[{"icon":"🎨","title":"FrontEnd","details":"前端三件套相关基础积累。","link":"/FrontEnd/Git/Terminal终端美化"},{"icon":"🚚","title":"Framework","details":"总结前段框架学习笔记。","link":"/Framework/Vue/列表最后一条数据删除处理"},{"icon":"📝","title":"Problem","details":"积累编程中遇到的坑。","link":"/Problem/"},{"icon":"🧑‍💻","title":"Interview","details":"归纳前端经典面试题。","link":"/Interview/"},{"icon":"🔐","title":"TypeScript","details":"TypeScript 中英文档","link":"https://fxzer.github.io/tsdoc-vitepress/zh/"},{"icon":"🔐","title":"TypeScript","details":"TypeScript 教程","link":"https://fxzer.github.io/typescript-tutorial-vitepress/"},{"icon":"💫","title":"Canvas","details":"有趣的 Canvas 练习","link":"https://fxzer.github.io/funny-canvas/#/a"},{"icon":"🤡","title":"Tailwind CSS","details":"Tailwind CSS 案例练习","link":"https://fxzer.github.io/tailwindcss-showcase/#/"}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function a(s,r,o,l,c,d){return e(),i("div")}const m=t(n,[["render",a]]);export{h as __pageData,m as default}; diff --git a/assets/inter-italic-cyrillic-ext.33bd5a8e.woff2 b/assets/inter-italic-cyrillic-ext.33bd5a8e.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2a687296748f6b8bc8076cd11bde49cd27e4442b GIT binary patch literal 28332 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 HNCp4^t1hY; literal 0 HcmV?d00001 diff --git a/assets/inter-italic-cyrillic.ea42a392.woff2 b/assets/inter-italic-cyrillic.ea42a392.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f64035158d7e4c01654e3f23dcd6e8299928a28c GIT binary patch literal 17824 zcmV(|K+(TGZYzoV0yihRy3;{L*Bm;yv3xXa1 z1Rw>42nQe=C3zL>7I?PUshK)MG!ta^L3b^d$O{#w!;WOi#caU z9epdi^~z}FXC1zMc;nw||B-~iJKZ7-`H(Kn3lKjZ5N5RqaHof~Lr#JsXW1jml58&> zQGi~|0cnL4zB|P8}0t5&U@c|JdMvNGlmzMw!d_sgsBSwh~ z<3uKERMdzOA;C{wc9u@*KWk~1ZrQFoOIvrA?XoRxnU;2`Lr2EaDbuDiOouv|*;F%- z#gKPJ>8fl=HUf*mFq&P*op#SRB5uMwrI5O=D|BV|t7*jYszMn6_y=vT5wbG)8zDBN(kmfH1b)al)=7_XtiK52#|ESncdAW0QK2HvRY`_;WiO>pz_-Xk zH!T)&YR`MAJa7J@pNA;Ve=XlUuY2Z4Y1bh`Bcza^p&9I}QLUiMj74g|4NyqjXq$hi zG1}j&v`P|}Bqr@5l@eV;qy>fq`v}SgHrfA#@*v!mV~$a+B6D&Jh-sRueXL+`%jr?vt30*Vq&Bs(79VL�!Z1%E;0yxE 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 literal 0 HcmV?d00001 diff --git a/assets/inter-italic-latin-ext.bd8920cc.woff2 b/assets/inter-italic-latin-ext.bd8920cc.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9c1b9440ed419d4a71ba46b0db3951164f9e10df GIT binary patch literal 63552 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 literal 0 HcmV?d00001 diff --git a/assets/inter-italic-latin.bd3b6f56.woff2 b/assets/inter-italic-latin.bd3b6f56.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..01fcf20724f915f68a974ef2fb85f86f3039b1d8 GIT binary patch literal 46048 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 literal 0 HcmV?d00001 diff --git a/assets/inter-italic-vietnamese.6ce511fb.woff2 b/assets/inter-italic-vietnamese.6ce511fb.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..e4f788ee02bb687bc1d5045483ff0d381e7654e0 GIT binary patch literal 8784 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 G0002QVTgqQ literal 0 HcmV?d00001 diff --git a/assets/inter-roman-cyrillic-ext.e75737ce.woff2 b/assets/inter-roman-cyrillic-ext.e75737ce.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..28593ccb8a4d849a746f2b970678fe426cb136e8 GIT binary patch literal 26600 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 literal 0 HcmV?d00001 diff --git a/assets/inter-roman-cyrillic.5f2c6c8c.woff2 b/assets/inter-roman-cyrillic.5f2c6c8c.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a20adc161f433a7c4e3d92306301b9228bcf9fb4 GIT binary patch literal 16780 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

KZ;k8ywA} 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 O1{o}0SRMEP0000Yp_Hru literal 0 HcmV?d00001 diff --git a/assets/inter-roman-greek.d5a6d92a.woff2 b/assets/inter-roman-greek.d5a6d92a.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f790e047daa346583880da2be470431e35aa6054 GIT binary patch literal 21776 zcmV)1K+V5*Pew8T0RR91096nG5dZ)H0F~eX092&_0|eaw00000000000000000000 z0000Qf-4)J030emNLE2ogenGLKT}jeRDl`*f>bYT3f2_GNicz%3;{L*Bm;zQ3xYZT z1Rw>38V4X7FN+22R&1!9099AL&6-~nb&9hR8HunLjFfWr|1mj{u|WmkXBLqqhgS6B z*89rbGY9tSl-Ogqov%UQJyVUEtk5;ACT%y9qe?^~nPX;~WyInH^VH$7f4KDd;6Hr? zD~+r>XrgNl{!tJRyZzD;8v7*4h39)-U3KpJUteFcWXZNH%b^)zj1jZ}4ebV#zrJK! zfB`oM;|2o;Oz3V8<6%w6`j(*+JLTG9dSYTirgoT+*%>x7A$zKr%yxNq-PwfJn}5vB z&*5>`VW}d!{`|A6Y)A-2bxqCbN|ypUE)cx-9>LRE ze)YP0W+(X!O78~cosg&Gyv+fz0u~NX9y=ll`jQTS;raLW$K1^|!^JR+7L(D`DrK=U zOf4-fRxK%u`IN;fNl3Fvl30;EEy*X6B(3sFFCnQsNvc(=B(zt1y*){*CRdoV{~lR3 z1`Hv&UzWXY-g%E?V;nZ`y#IN;^N?h5B+KqP8(!*SiE}*Go9FBr;($XO)&z$rtQ-sx zjyaU2T z{loUhQpb!Qe`(Y2@O(e^?cDdpcKd=?2!*KXZ!KXK3W-gGOo&XU1o3;Wrfv7~YBzBd z-yMT}VQBgat*E@E=2tk3Kze5GQomIRM>oN}L<3wPd)&_fTD~-WJ^jBW-=BzQ5I)Al ziF7Y%Ynz=DT2?gSnt&C1;MRZI?_2%%pEWzX9$#ArLi?G9H%cC6bvT$k26Jh@LZuO^ zSSN`kJdpymi#CgizgM+v|07R2@S?bp&e}pA>|L{=XdH577o|HF<>v<&0EiNZ4F*Z= znS@SzASHPrLfi!?@irvta&(9R1eP{PN;VaEiJNpeRt~Yuohy$kw;^?{J2$Oebnabr zg^Si!V_9^Mn&)e7&LfGkNC<1yEizZ82tO9y>fhnw5o>Kj8rxEF;E#QcX|WK#U)k$D z$yo?NL|74(Wd3>x2Gz>7zbcYgYam#WLcrZvL5P(^SS=RfppbB2gGSEs7S1*&%msyc z6y`gy&7zP7g(VJLYFStb3acrsbzrue>(?4W+A9tS5JY_!+S@MFd7H|N6-VFI&ky|LjemdK$s>duvoiP2Z%_h|TEz+W&ctAklq2kRv{9(Xk9Z&O&V{VAGWJsS&wVi z4jtMlv`drrtl*#y2^?N;5~QvjuiC5HgC?2;E}$pwa8PS!qJk;apRHE} zxvi}Yf-kc>C}o82wO+({X!a9NQH{~`LJ+ctW$;pLlvww~`0m@l=j?X-=o_-#T9Pue@ z*hw$BPZ$$1aV{EMcrgu5uIx{ff%q6uI|WQT}Z;!{ik4aQgX(0%MG4kW9yRzHk$5z>6@R^95()y3rjEJa0SJ(^!bl$jz1p z#-zZJnr+|z8D8WiUgnk2*;+U6^4?+L2Yh%#viDB*5|oLn2a1@{EQSdvYCiE16SH_~ zk$|d4lQ0m6A5{pTHjU7Z$@Z8sEC*v&($6X;tfoOm^;kp2!I5El*l42~MwYpiQn*v$ zAk~CE4KWPXImaOHTAzX9VJh%J%sjJVylmB;7Qz=29X02g2%rKsDy1kQ0tE|#n#txk z+7m?#3I=LbebcDWm>LFxsll$uYP+QvfB}U#{HQ9nwpK-;khu;F083^AfFELkCb>4ub0ac(t0g&={O1IvIcH~#=a;HMdAw?>O6|vk$Amu1QDEAY%a*P1K{~HF1 zf?{ebA-ykQJ(Q3>n6N$^a`!}{?+mW*4yJpPpm&GbbA#%+3F)(uq#PB%jMUS&U#iB| zmeAVL^6_qa71H`Ca_m@sKKg!+j9uF7N&)3=18(hs7S24m!NB-hua>oxmhuf_pTd_o3%a z&WnP>LwAR|UcD_W?EH9WH1}c7nE8X$k?^EX{x)N3p2>`!PY?)9I||wUMIwhm0Dr4h z0f3*&#P}U3b)5ojFg+)9<1p9EmaQANwvA$ACiwdUK47MZ21z~)ODtd^`Smit5io$- zrU05ioj7!OR4f5hPpx~ggdm>fbw1*AG5{b^gn(*g6}>B~g}SmvReP^|=RzgOk|c*Ei)G6%7-V@ex^ zEt9Y#S?{?6qZ5a&ACph;;Zu?5uCd9R>5Q2;`?QnNr=|gg%%8oKoxA<5v0-G7pNk%f z8S8Q$zwADU#cveuyz=U6!===DWY@sD~(pc$&Ap zObrn~ootNzBLCsDTNH!KOTKca#! zQq_f$djoOC9V4uS^ zq$ChF6jlmj47EnNtC^I6S&#||rIFb#C>ihyC@^D27BgUqBFGk&6YRuwx6Stfmy>`; znHiH>*rDq#33t%BsnQym3DmGtu$y*7P~aS`nD3@@HfgE}Ii!_oRMGdWc^sJly1Ap0 zr^^bydhsd<)lBjhzfFA+pn?cYK&cR2raY4XxPQ|nVu*A!`_lmvj{~CsT@>+KTfoGB z!F>X6Nno8btLg~Gg%0rI_8O|^b>$Hq`2sL~b4q9=IYt6p%Scg`D#K&m!sv2b8b|bK z>L{nvuBiTP;(;sThRHTjP9_vjaZTUNZ^}=)QW+Y>(d0Q}&ZINF$BUKp<_j_I&qmyM zh@!RlVhUU!DNnM>!uA4nWH+h-FOi*&jqVi%DuLpDb35jFi}2V3t%dJGch zOT@d$yq0>^E~|dy;&MDH9mSR3MW#O7n>H!Lg4l)niV=;Yqa#d$QstqS-;#FFsri<`-T`PHF|L~}o^tzGhwtiVwtmfmd9;COi+2b?+;S-C6xG8l+ zaBjpy15K9OOm>muP2-S2kuNf!5z!4URW4dmcEdO#Nls)xC6hH@m#t0Wcm##rG>-#%|I{7CHuYKm~&t#s<4;@6H@^H)G6|^TLh9; zoa{LHqTFB%vJKjz8nm{qx65;#IWur1ImyvOtYz#bQ856Q*)BkpoYwK6=# zyMzIr#5TN{@UXhY*LK&|Qrf=vOFVnka;!Y_rtZonD^@f!*kTSp;e-3iHs7!8yhM5D zx&I5yW1Nv8BQ`bFahTdg?zb(W0oZd3$eWhDIQ5EG6e8Oe`mX(QkFkailJjZe|HQJeYqCkP-URhOmL^couHQ1?!9<2M%1E2;0hd5vg_RLK^1d%Iu^Vz)V8 z*oozSMYF?fE=%0|E^LN_zO@+EihDR$vLuYCTq_bc^n6w9`^sf(7Pn7kQ5yNh@Q}Te zRo!&Sh)D9hc;+!2yt0YwA@%4KbHbDV1s@n?FQObR8DIul-gz>d%GnYcFsTfB{*HoE zu!M$OK5H8B2mrhQ|&4aX!RPUR5zB#;GKv;_npD?F;z}IXQt0%P=nwnx^uy%g0FU&N#^V0{t$(F+F^Owb+zgr8Nlmo!NHsOnCpP=YEAu!|wi6 zcCY{TFMcrmEQzoA&7l`vCq1(KH$fWxQ68c8@*`vjM#C3Y-r1D@PYA}_^3aY$Pt8c* zq0`$V>!Gl4`!D@LoJIDTer9>ywO+QLM?d*x{_;>95#sxIee~WmalUPr7w7!{Fu-+> zR3T#N|7Ns|VM65EDbg7g_mo(2$H(qqMi_evPHor|rVryUKem(rQfll!nTX`CoCnOH z^ppL~`8EI&{f7dzc6~ca3jRPsJ!RRN#~;vRrSJQluQ#lfjsNiD3;(>c4!^~B`!{Y* z55B9eIQq@Ic;fQ~?bkl}aN_ost{r)LRYI)XxZ|wo@U8Z~A&^!l(cA72ovTQ`k3q>4ICVj9w>_zP z+clHU+3nC1&zzWg6RS-XzL3?16W{H27@AZo6>3GBRy{wcpJ2&l_Z3ztm_^>aF)+p& z9pDxOga{)2Q;UoY35XQ@T0DHfYy^7H*Sm|Y(8pRE&>1H`oSEFXL2_#4wxpAr!kQ26 z<#x>wmdf<3#a)WU-9jo=);2SX0+!DJ%8Plm1ag#{Mgt~>rvQd2JV;zjp9J&nnac z4BEfomZiVRmPpju%hPdW@GomUx|PX}u`E~C)=*29pW1JC2_f*&! zr>4f8@8TCBU_b!sNiPk-fPCNonaz)=>9a$I5wM#~RtwY-VKR5|#5w>b*U4(t1U0)$ zqSmWHiVFanaOi{g_5|F|Xf*2pxU&(X&2Ry@v#e{FxWHKDAE0#MDP6>&CctJb`m)LG zgWrZ^jQXJDy+IH1|yBboKe1}R>7xt#ongtsvb&hB-w_MK$D0cB^DY*w z8!sS=qhDRB+H0TRR22RRc$-KA;x^HlkoBpnL{DVR4c87j%k;QUV=vcby$d?hN=UA{ ze`wjfLm7KU*wTQ3%c|hrB1+D(qLK%2(&fvT?Ug;&1$silt%Ij4Z|5cnYWLK)fzU>f z9(Wp?a=hy4h8GnHdr!u>-0;1y=x%MaAWtRUTAb-09Go+6PVyRoQ>I%N{hfvK;Nlm; zd&j#XcYLm4sab$%S17aq!{{`Aaq8=$X2n0*IiMR%R0}XDzxk+6+_EkH76^0j)C1}j zfS~%FKIzoe(J`y*>`A{#`k7vtWZ=XK)-$qVvpe)0FK|+hsP}?EN3xZ?R$2 zy}8J|OuCo<+?&I|xtT6{+>^Jy%FaD6D*6t|Ay)yo*GD~GC>I^hyc`&HAoA#F+2iio zzNd_|%P)=>)j#vx*PVFR88KeiSKAHDCMPRzJ-h6A+U=fqT~0Cx{@lr=6RVhK_eBZk z?I17T%-lm*ZMl@`>G6HZAAvwv57fJvKz$2f(1L-U%N3>gGiI~QZPltcJNB{bSKfmA zD}k>URm~$bw3Ppwc3!=~=MHh;RFHjJhhivG{$cUy(_L(j3!6{*#w^?~R6q}(Ybw$ndV2`Js5=GUYUJWf|vE!q?u?6iNuutV~S+-`>#yUs?<{`*6?bPC?r`Xp`6e~+{P zp3nljHh>$f6&ksXWm+_Po|Gvx@A}&NUhejOqd0qM@=i|TjGpe>C~3kaT}o_U)m+fxvgSWfHQBWxQ(4 zK3MtK^NAPAJkKn}#F+CzYhg77KLuycH_EjLTx>K)xh`Lsf)uA5_6=CW4+~qz4+vPt zOQtov1s(oD>oyf9ZwkU*1w`;%Xq24O)pD9Ku-tOBNF88&`%i&R4d%agFk&A&c<5_z z5+}G1Bcz)~MVShdgc;T+TJ7J|L^!>8_66=I*J3xVc^c4ZDC^l5b4SF$%HhzpB>^=s zO9Y2vl5FGm>`%A0x?=yL#u(tE<0QM&IqvU2vyZ65x>k>cq|4KF^E!PPV7l{L-7T+D zzlK+<;cthGkDNC-X%ZYHPPr2-71v)4mWm=C1$GL+I)bQKg5rje{zW*Qc(sgv%>FG3+KY9`N>^&*E=tye~e#<^8Ne|A@!Q)C;Zwd$-1T zGu9{UPP>>R()cX79ufEJK+@~@mMx+ic?F?^wQ2eJO=;nS1rOQ=0nW&66So29dI0QI z2o1|SwJL&YDGD{@ss*`i>OM8#RIdOO+_9r8^~WU1Dc0x^6&z_njybnHErWR_)!-k< z+g4p|*SZI?`30IQz20I5NKODO@O;j5Wia2K95eT`wObAt$N$9Tu6Z&62;~LpL^aX4 z%Aq@Jm`i}DOJrICgf}>J3x+}YoIC&;uR)09QT5tQp6(=Lg;rwKW$7datG{#cgTZ(J z4qHHdfeFC1mj(_Sy_N${I%zdiF0Jf0)377nu`xF_drvpMNJ z^~V*oAY%rxBvv1o^NarMiQnxQg}*Yln8!Oev-U$ja<4pJkok=qHP&<>{BZ`cGW-) zejPp@dgAu1h)!Jg;+XhgsW|CQaFE#1*yrVc5a7?@M!&ozfDyoFeU6RDnf@vz=7r|URgk9jS@#uvRnW|^u+?7k7b1|*t*$kx#du*t!}mH zY+jkq-h`l2vG?byftu|NLx$0N^svRZgW8jYtec%7d|hBk?whQNnN)SE#{Uk0p|8t) z?qyw-g&fKP7!a`Vix6{59{wxD3p1B-ya?aj?su%W00(bFCTk+I%R*yL)GI=C*_?c~ zzOnK|b$zc{C1i5p1lpwJ#vAv66OjX)p0aSa{->95$Ig5J8`lRO;A{C^L!%x8#T{w- z!12gu(<7~z6Qu_9K?p8x=_;$ZP#LVxr{@RigS{fRvmTZ~=%ck-Y?0wl4ILOEInEO{ zcU^~DKBWt_XlzNP&JR3R`eE<%UU9-c1RSh@#Xs!P{{WUeIrQScMIO;d=f)y-8W6l* za`E6=YFBstJ0N^21Ovz?>OXuptMK^becd)>&ff6bA(!X2@7oj5x;LYGdF<>c3sur~ zv9(B+d@MDvJ@(atvreu>F0H>>AP@fJz9zq1C|z`1J*fs8$7>ZAi-Je8>DeJ8 zPoZK9wWFBTL*Er;Q5mf@+qcQA0(ui&a?4>)4CqMZ0jL+itMHDTx^Wo#fWh0{B-gQ* zPj0p7>N1w9wXc%>J~!UJ_VzE2NfKe`zE{BMN7M0|J2g%k=X*8D<1=f!^7dTt^-ss= zq#vdYP#MuKmWxaa#~gsNfDu5o0s&x={L>XfyBQ`KYzgyb3DlJ3WxiS;7JfEk$d;`T z{V4!`n{PM)$m$Wcu+MdXGl(K7RwO?K2gsNMio8s&Sb%Cl8+b4m^RYmSz!p2xqwV4$ zMbKWJwa(NvS{gdRkRpE>od{W$!UsjEc-4fgg0S)!n!K(aFnAlq>B0en7S1?dBq>P( zpv@vl%jo7~CfIBt9zm+QlrPY01fvBBrImFnKRW>Cw_z|zHc2U6l#lW z9b!5RFcfZ%qW972A(+r~zLe*nky@Zjx0nYBzNR#|Gd|?UblpPUfB~C-7St zIQ(uQ>3lK(2q=JT`e_!}^8Y&UR+htI4;TFt+th9J3XKyOlr@Ts3Pi0zMWe*1yTsqb zJL0oxq49F#WaA9utHyVXADJeyXG2to4pl(sp=;<_=p^($bP4(_`ic3i1&hhVwjR3y`@S^L>|yC^8wa-)myG*1 z%4>em!o?!U;`f-KWi4WdL?g+_gw-OeV5^x@azoAAGFakfsj zb8TySs+S+y+V5&S-`5ED`_*1|u*4yrpoCvpBfkIMj|+A}WK`@Mn@? z3UE3fXH2_d3EA;7xw3ixy-)36@Me^4V7`lO7>qTE-tnlT|9SaRtC`3Nn)zU+3D;_^{W(O+{8v~)QV>vpLkTJ@ zq;vKL1NmgT0waaXOnPLa@Y*cDMX`;I@mXUd-wF7 zIa;HImSjzQrI2z@&YwPW@Wz~_R#LwU0-DB8!cYEMg`O4rh&BiPdBOTS9hW|>TmPLm&!KuY z^z&C~a+5ko1XmV6@pRd`bzMV~fwdh(F=G%>!&g~U(}Gz$T~*H9 zk)>KsAVRc;Z-)BJoWUH0n2E{1i0qlGOGps%xJFs${7bGxD1733hN=JR)$+4vD7(DWueBR1h`)=%j^0aWj z2Wu|8*kl_EDKKO68VD?4&z{VCJb%!I%B@R0PuJ3JWpG^Eox?lT8ODRv<+_3KSMqe1 zl1#}F>VCRTMY;Q-2Frxtbns_2U91kaor}*`93cm4NAq0J6(1qzr$I-ugi4&|$p5c< zy@wq=f<3EH$v={A(6&j3yK05-5Z7-1;zvJC(qG!gtp0~TbqfGNk|h`&PEus?Sa*OA zH|k)(I|?CMMb3)>g(wI-fE&y&vhw+f3FfEc1ALlp+#4$`(8*D$MOzj*5#7v1g-x~2 zu0!o4W=P<2_r=#MnHeK|8Am>TsW8%`RMA(HUb;hod9b9I{2~o&RQd;pSUXojf?QZt z>h-#i4oniJpHz^e;61ur1bi6;VXO+$C{oC8%3$cH-5`4~GNll{?iULY7-BYoCP*}} z+`MNWc_j4pe$;^@BIXBd5mD;?j-zv6YOcri-bKK2c{rG3PDWXn<7zpicsKlVNjaxy z48BhN&ryZQXaaXcIV48@%9Tb86FTKRw(VA8EqCGaSSq72;HHA9Tm;{)Og^Q%l9c>1 z%pFvd=rVli#Q!-=t@G;vbrU+@4H1Q>QXW?)4-rT>nfSG!kjkxY@j6vfLhxUXZEn=I z9rR8|bUJ)F_mF-7GZ|zS7$dPEzP-+w-&djXscxyD?VJV1pR&h9o=i_X-bGqEX_v2( zB&|G>W)53*yhC!!!8w>iUyK>3f;5oVoDSTzh`uaw=GP9T#AI1b^N!aXaLMXwh8@c| z=APeepB-Zs*Xafmz~+o=-=&?PXpp}1VCO4BLnzVQk4ZzJaOqOTKSwOBU*7OlDlb(! z8OrX*y!zQ|{JhS;{Bcq3crxQl4(=uBO2NZB+}7y-h&m9l>5Hz#!0HHB1ZMy2VqlGh zk6Q&xURc-(WFevAfRvAbAH;?7pKQ6(O-ck&$W+3-9< z=i^|FY&Q5z4^=EJm$58;zT7!7r#7IjkQmYMN59CxUYFJB>-QwiI=Pho$AZ2?j#H%1 z2MsQPPvfg(`%>f{p7Qs~UA2*@HJhFaAK?i{|9|gSH=+#qPUSLY@Vp`wz=+(HLx}Hy zI(tzk58Tll8%Q`>tB$}^+d-|nhTuX8?xgDxl2efgaLw$4$dd%r#j zj)D^bLV~0Sk^>q(SN->3tpK=r@wq`*J zxFseHsaDz=w~Wq2-wS+zV!euTjw1wh*yXTegr@K-w4*uB1rCaM(Nfb!$`Dvl%vgTZgk(@Ot5$bpa{hs+o@oT1Q;N0~VkZBH9dWaK~ck%aa{zrD+5L&95l zuhGH6dSe2BhC5lr7SM>sn%D(DEf~uzJOxMR{ChclUQaIFG!1&PWoA+H`+XAmGixML z0RlC$-6*(8`km1gEpr9be-LY)K}z{nl%u!w=eC@4mk#y7mbRe{HYixy$f2q@h>IG_ z8-dJ_qobNW%VfsinqgQz(?#QWw0hYe57Hm|A$P$&t5*h;MoT^V?os;*a88D9Azkkr zH%d3qUBH&K0fM7YK>W~ zAWp25tA&^I0TQI~;vR)O}e5J$f|7 zwzixi-HtR3uX~IlLOdm+l0#%OrqzYIY~4Q1>ZnVZdR(lS!l1_!_icQH92RQ(Yi5dG z1YJLoV0SH=a(Qoq-TJmR?Th-cn8Ac*g1T=ci(e<=pkr#I%&~e8+=>!5b9?>-=ym7g zIX$tFFr@?CfB(6h4}=HPet&wGm7`p!-|MHNwx9^B#TvwT#*hYa;sVx$)ncYo&N9x- z8y;!bJtSF;;chI71LfgrNORx|p%#s+B+TbD)|C?;rCWRD%$vUX)JlfGt6l@8>E786 z+SvVqx^)REqn#fu>~{N=63j}44z;SvN0_6YhHCvuVLP>u@dJ#B@f~jiU?QixgbUib zMaaac6i$3-(J?GK6!DcL1QQxClq7+iqVKw?cnTEa5a zj8An8`bZ^vO=m+O99%q|=SZ%R_=#KZilk)fhu=xJ{^9!i#>Ut`2~8_RDS!m0a;G?Z zu9WV|6VN%}3Om||Qht?=<_MffArzdX&*M@Ibhk3kRcmalUSkoiCmHu z*A6asIS@T6aeV917rK*Mk_5Pl&Mj0?H|4wRwYG%A)#m)6-l^{9=N6%sQK?gxVV&5Y zw4naxbwp*mAmFtGML=x5pnM*DEF(PBnL_WLGb2d_P-+#!Rzd1HtW`X>TpiEIajY*` z>jhr$AnqE`szsMAqx3@X;xX!3LddrI8dLsAjqucItWXaJ0A`lmYAu=>nEK!OYwdy!pKZ6 zM`@v`92)>rHc3n7bbe4`e6Vd1=Q=Oof<%-zB8Bc9&Q9Tj1y?BOeY&1^H7S%naV-gr zNT49RFZ%Y<8NwFNeZ|PRz(^CO(TIU9I%GmYN>Zs1Up^i= z|7Gj=JCo=M_~lCrA|U3>{U*-m$*DyB?~bCk{y;j@cR?J&9C7|&}s{LgBX~hV{5FJFOVYBL^rb5 zR~E0qm)PUsAt|>sCr|c7g{$|pn#CNY6_M?{kp_m|u#^zmjPNg;DTW?t)S`otOpS*z zEW%{1M`;PY#;JSEFcwGW8cjltn&<%+>boqjR|@Xe(ubGQjee>$bWVb)h)n_&c~q|6 zx=92+wNmmL>~6XUz@HxH{XGAn9w>d2-+Lz-I>u|v(O_h(r~aqKhdoZg=3gszwh{9< zBg*+50;o=wc8D%09t}%hx)B8FwI#Q#Ak> zJ$I3K#G%0UQJa*4w5m;2zm4s++ymy0Zt~J$V<}Mx|Z)HCZ&x)Iz3rTzoV*eC?(n zEmaMi@8q~N-g9w*Q-X#6O9MjqKknHb!}nI;V;*CkdGip=<`@w)G*lAwPaHZG?H1NU zTS!O!kA#WUJ{j2&vF*$6MtLOlWYNfq9DE?}_+11LyrbN1xTd_?-rHNkoY}QlBFR5o z{dgQ^ZWBZ=$7(Zrb$e@zTpRCdH5!8zV-tU)*W|-+VX&aneaR+3>sgKlBgO#&KWFqm z7H*6*l?KmviLB9oXb9_-(wvqE3=IvvhiM7pN7G9BA}I<%Omb0t&bl=~ zy7_Bxo*J6?6BR?K;(TAC4DVr^-#RWoUU65;r+bF308(1s$CtHL^@DuAkHft~xre6d z(ZS#XFF)dLDV5hoW`SN-igh3wCa3w&WmEDmEnc5H%rV$l5URos*Pdv^I4d0&I_ac# zuOVB(bVt!?vSa;b&Dg+Hl5QoJf*?{|NIROGzx>D4`;I$T(BoM$M<-19Q?~@dE`|kK z6gUoNrrhH#3W2l8l0s-fH)|muYWDNgh}-;=eAo`{q8eaPU_kOba9- ze&%*zN|=b9wuu|+aFIQd%BqEntKj%f6vM_=Dn%mZR5S`9v0sAQqt8^spea^g;G|PB zq>#ad;92`;b>$aXTxy`LK>OF~NE}>+b;~FeM24nRHt_FQBAHyh=i0P4Mc} z^KYHF{N=#(i*^C|=#NSGf}d*Z553~LTL~c8=rT6^*2y1Ce>mg==ox&~2D&zK@5u{$ z+*)@Z!e5xW+e7f_%R_7SC_)Xz(V|?I#xqf=5j^XTi7y8E5uVs)M!uwSdUirpG#b zf%6-ABspG2D}+?~eIFM4g?Pob0RX|11$rqR7sL|b@f;Nh5<$Vas7Elms#a^n0c*%9 zSDrgLr-xdKK;poqSq_HFFZ3<|sGz$d5&M4y=Dh|d`^2bdjmcENk% z9|Z>~h&Vj6D-5yJSYc3}X>?7M3k0mN&^plkCiQBNb7%%f>Uo6Gi$r%*&3a(lQt`GL z5&eC*O8}T5uc*PX?CMwdIwR7Zh_hpBd;bLK{q4@lKiDsA4dgjLdwV)`U+Gnc4QicZt{1h$T{cLjiW=CtffBt#mMxD^AMt#fLj>WqqSy>9B(Esz z7t$ZkUH{oKS1~ah`kzg!89K!B@T(43g#OUcHpOF7HqcNWv;_=A@}$uM9W6^^I9D{b zT1QQPp0CZ>3(iMY@gksPdQOQazKZ54T544et2*Z=_J$w`BG$ZfOHBDHzzFdBAlg(} zFDrlp+BpR0n48hY@gpGs=@Lr|aX&I0q!`5YC>I&z^N}!#D}!|yC-EaW;I5w;h>$$; zS#Kc=FBF`ZAb?$WQRMpglLvl(;!l^RCnv!1#>6|cri{wHH0bxA>o|HQSox)`CsdT< zX_omVc;ZtIC_$elEHYs$gz0n-_>LACC-)r!`7D$xF1d8O$*1zQguym6x%Kz0ZDGJLwKZMS@(-H9RM5-s0f~F{J0MV=f8@|dAlYN87Z|oCvPQZKwKr; z(PlF?*t`dsRXQT;W8pBIw=+Kxz8g4XS9cWLKPr*q@$~%a{la?oW~c8BDZA~`->X%{ z#b}=S~&E?d^bm zR6xa3*}Z!Y`riBoifO#L5E`f1S-Laors!3}KgYRdt}3k8*jGc$!09L?cNDmW_c#@W z7m0pT<KtduM;##!& z%!mKxhAy3}*?U`(uEh)7MCa{H$`-sksGYSF!>t$VeoJ`hN@m;Wg&c`B!VUANMBHz! z!UG$rO9v9pJC8AM98Og7F%Dl~KwA;4+q}6~RYpqLkCCrQ)LGXKVjLnUvX>f)TdX!I zTBFmZSM7F(uAMI;pA%WmxJ?0NEVWI75}M|$$>oYw3>UN%o?p!QAS>SX3ptt?T$XCu z2i?d93y#8v6z4;k&jxdpnSL}18KFUG0|q-FtzqEirN6bb{KLV>;9E`?0I*1lz?U}P zI}zo~j%VNQD%&XU82i=fc?3auV*;v@-xFdhqXtH@)Rg=#D!d+`f9&^7XJ0?sdbFwA z0$pppkxcJ6O|v&8&6Jp%CBz+d2~pNV^$JgcE(%#eKm!k^4N1QZgVH9{8$_Z`_?T<1 zDBLM9Sv(*AWy6yHiGe^Pt;~NrHp#G3Q6HBjP9`WjyL)Jb3t&X&P_Pam#~K)!CQQa7 zH8>*LuUeh_STuCnO^F59A`hEzCNj06+U5Azs9Qs1{COM7lFx}ZBgWgrZHks?6iRc? z@06mGkV@@%a`cJyOF0ccHRRUUQ+kvRGlebOB%*ENgJ*-H;j(`&6nHbc>{1CnW=mds z^1#OJqkFpWJ3@?=kBBO*>5sMAvIGuo26*q_MtXL-HxlVp?6-2%Nrov6xRQP{G2A|j zP~sttkFtkVX>fu?qjMbkt+TAkQ9uEllvN&_wliMlm`e7;+Mgk102jD?W^hVhy@I^o z3s~71P86D;kpu93Kx*^)D$ZFDls@J+1t%mgQ%Sw#(WtP#N- z3Xz4vlyC_azWB&8VF{J4Lhk^~sA{~`6v|6Cw3CdVRasPY=Q((D5x9gEz-_)_#pPFD zJDspDI&kLnSr@-T=*dAz8rD5LFfdIzETaRg#}Yc}ue4=YY0DqjK)4FeVpzy5&)!?% z#B$n=xE<8xLS+g4CeMk{a*35JwKq|_cMaHlwmM1p)rBB9JQk^{6i6zxP*=kk9V(fT z82J3h5-0yAiw7oPk}H-aU^5iBj(ufy&wEY1=RYkBHG{)fugc&z{H2siI3S-YCK~@N z2X3FbBWpuf|h@+_(kRu2pEK24?a@yfpVKpu!<+BwcDy z7wTo)-NhnaXpAWwH|AvOU4ujjBuh6qkrfAsi_pZHr)F%6cO^DSBRYrVaJMkH;5-Hk zqhf7FY9UCeu`;v9IV9>_Jm~$wnDc$MYZxUpsS=v3mL*jOtXA61!2z^)PT03*H%*Xn zZzk?i-~_!i;b2&1@yX{2d%{=4LdQ9uiceCylx%;QvIk3= zl+vW=@x_ub-#iPG`?6qgECSXxCcwwnDJk-_c?;ob?LqPULSCXoiW<;0r1V51lI1CG z?-pw?v&4))?T1rt2{TyWCF+j23mG`!<(>^OFj`o~VyrZ&-%M-TkeJEr@vWkRD{DIy8f~eS(#)2n98qz0W3Cozem@$P)o8?n6(@qs5{SF#qK!rc zuqi#?LiX@pyqvXOaFP%&St1NpbDo&e4R5@cg4Z%sfFRr%fQ_>0><>jDHm%E;zKWY^ zbHe5nVd@sL9^+dqq{LKSNo#`wt~AMe_H$TY)HQuoSM?QRrT8w6C|3Q=jk+?n7oYKC z;+e6pyNf9#PUB~x31)QN(#r9=#tbW1d-lZlw&D(IK`wh9N=|dzl zDQObGswRiDsRE|{F^gF;UDzady<Ak(DLs!UtPHPmQi|8_{f>DlG@VwawLTJnv zZwyR}DMP9hd-vE=s1+&Ejl{*>azu2b#mUjK{x0zognrz#RU$JkY|kSJ;h&a7*C{EH z-4Q6}U9yMMQu1RWHD}2oG5?cF+~Ww^@cGQ^e){<=5npn3TWS3)Bb1_r=MOB?|Kh?T z#RevHLEaRS1_P_LPioG5ilZ1zO-t1qUmLC zDDy1Sw~N1;0(dB5^~U?YUjLYh^Gj(8Tp z2=H5M+toAS9h+eN9-vw1$3bgIKZ}VcMs{v3JgCfvv{+*fdR|jt0u~h#tSfMQPEo+Z zkQEbI7-MN`@a0?dE~yoq1(z()nBo$Xy)RSwSHIaMo_jY=&VR6X!`B2MDBO16#jIP9*UFUGF-s5+v&BNBfwens7fTKGWRR2Uu*fh0|PZ;TSL@lttA+f zMDEQ);(NVec;?5Qme*B%Q`ZbxOL|tH)yMS-J*}%o#euVrrBF4OverQDRSDT)^%^3L zd%Z?&V2m;Nd=>UC!#?wxaKcnN0eL}CCJr#b|WmN-ElU!yl7m99Nouia3g? zSP~a6aTJ1(FzGF{%Pi_4I;uu1bNn1QnJ=l*i|{F@=+?o>V4!DQm|n)f)Y~6IR%eTq z&A>3NvTgt)z}G6{0gUb1nUHRUVntSYsLbgFq)Sr*s?EV(D6U+yZ{NTZhYwZNiYuis zTX=0e9y*NeZ;~JH4)z~#cv4!d&tfl@o{E}q_~A;BmoPM=5qv*=`pN_ey_uS}3}iMr z6WiEA-ZYk**H{tB=0$vp*s-8m~A38eTqe+@h~qy z#e9rc3nE5L3!JJF#fwR9+7}Mf%7CkIXCmXfdJv5tpKRy8J-WgBzt7G_PkUSW8atl3 z6VxD}*n4i(Ql)Q(hua)7;#ZnfO(pLz5(R2EoKFYdRY`Ok0MN-9oK(|OS#?tj%}mjH z_F!gCg4;S>Mu|9egl_)8zje1L!yj?o5?QJq_AVZvqACRu*KIqT6;sWwXvUWGWS^HI z4qWgwr(&Kt9u|THzexsfZbGI6ENP*@Z23+HQkX<%pcEt8#vxVehEyY_nS|0)+Jg6F zCyjlZJY8fVY;%3Lu^2E>)1pfD^+;3wP*zI(J zH_pyIw@0-uJ-lsYS4!K$@51crAq2Zi^#CJtWIrT1@!L_&<6xSF|g~*ocTdwIGp%AG+v~&|H^2t8iHf;8 zzGP#p<#OR1P!cHPFXq4!Q&={cyt*B<63ZhA#@HM1K*aro9 zNEN}ML9ddG?DWl_1S@B(OHG?26UGGn-M2cem>Q6gT1ZW<3)nNutOoNLJBf-ZyG$7lg0{K?Ay$CX@bn9$s|gSB({~L=I=Y zXJ2*fi8H!y;3QftQ-v9?Q(!yRd39Ewc))x0 z)h+J`eQ*&KHgWOJw(&qmO8`)j*90uMcKM$=5a+;o)K-Uz%T?6Cc3>Py#Ic||JhICB zM_NvGCKWl@)Oa{B5FcGJOUbFx@JXgxf~FSl+Md{>DqH_TK3)Brn7|(ovk| zip441B;z)OYo;Z|&FuPU0Zp1K?j$42Ws&=+`4eB@yQ^M>kBAEu0uDf?YMJJ|yw<*t zwLjd-#rEy2smS>w^^9ZPgZ@yp&5c>QIP(guTsAf&=0&O3bkN#lWQ+HJf2`=4sgNL- zwG7hFz4a)Rs#`>(?aES%aZqpwzxUYdp^MncsjbZyx{=Xsvh5AN3tgeERhTi?M6cFL zJXft5%}@euwSI#34?T2A$>JMgB~+?ZdKv6TUlXjW0O4}W&@Zp;D$IkRM4KNopYpPk zlIXt$0`38EnxevoH+Vwz^TAr-us8o8dNrW{D1gQak!Sc5Q8}GoR=Hj^!F{IHbnv*=S($jrNX2D;z*ufKZU+jj;NTUBUzTAhgp1eSj|M7qVz#{j#9n++^M^Biq1lPnRDO+IzNZ z$No|@|7s0_MZaZ6aAg!Lhajn~M_a!+&^csKAP+?0Hy5y!Up2*cZ4^p=VBH15U*v3d zF#>}7C)wq+?lb^!B1!%MK>#X~1*3&~aeru2hDvJL@J)adj1ZgkTg?gbJ)Jf&M)MR& zgvG!dqf%ReFk_fxQDJ=(=rgct8jP`y!>kefo3F1-K7;jCdm?w=7$0#wPBV4TOFr_U zfqV>|PNaSr*;Pj8kfQsm6A?2wPbGcUnAhuk|0u{5&*&U1H5Fqq^h~6ZTk|1@uM0)1 zkP#s?QXpp;1oARxmj_(Lw#RLt^wj^2N}wo>~rxV}xoaZ-k-AcsQ@4#2C6 zz_J=l9LI;)7`;zTU>hV!%nZYt*!M%%CbAzT(k}gUww*G&QT(BPYu&fuz{#^PQ}>uL zJ*D=-cPH+ud%}zO;-=U!gfpOD~-b@wPO?zYLvN;$-}$8%DaM3^=m6uQ2y% zjW^6Q`N6CUsZVOa8BMuOL!IQKWNTH52BF(-V+@$EN$?7XbA&t2Qmissblq92E&R-R zfxxU;YBsZ`pHfqtOg~~3kO4;v%tT@`+B|c^{Ap=a-E-rbaZ59!3Gw{FmrwuGvist@ z)z%%AO(a~E(FgmEed3)*Iw6wVai7Bo%-g&N=CjbCttbVXbFGwgT*1nn%0fdaS@|LT zm8{-~+hQo<@mN}Oi(qe_09xE{OuuVF3ml6sbk4zXfwMEc`&~-ZpjzA2J<6$0P6glw zaH}22H+M=cpi*S)s)cmvq>W?&+~gghG{u@H3l-BAGgo_povz;P3gY%w)Rn&NE)<#! z{6E+avRd48y&{ZvyAq%LAhr6BYRr?A)5LG}<(R)E+gtT)JaI0*xNW;?C=CHv<>PtZ zM(^qqPsW@mVh7x{3KX!Tr(276oaK(vU8Xp5`c6i(HPYfYx6Oq<1c#6uP**M^ZHu$g8NV zsIF&69bN*>DDwN$q}9RM(-rqtx$v*O*F$1DZ{Z!M(qf1LfG?kERhv$oQsdz@Yq;I< zlbEN04cQE97rT{bu*>G{=v8g^YNJkb-dBm`?{t4<;-8fEo{e5KiiVLArQ?r$B*OA$ z(3DRR7mCLda?d|3f?i{Yg1f35z)dKfkCS=S-S*9l8%!GX8GYOsHk2`Za4qY@n3pj| zYPZLo+}4BUE@A4=o|aXdfNwM&z$x0Qf_uJVy@_ewlf>h8C)S!S;_hQ`CRjJ-Kf!;| z>CW|=tSEo6e4zZ?SkuzhSe`@Q)t7{_Z7IcT(alTM-zZ1rBx?NCDs9IS!SUKr@ITI9 zfbbEwoygE1q!Pi5rewwFCy2BBC0?U(#a{{}1g93)XNixoAK-9DZmF4l=#sk#`Tb9wCMWB{Yq*Vo1 z+hO3AS0W7AMUMPGrlOfF$Fr_Z`Ar!ls&M0176eykr?}$HR`$D?I9XnHi5+yz@(D z)kf`1dL~y&-F)QO=&>W4+dkv8v!K~7oUdx;I2}d;52wGRz-LLXrU@ie84Cf!n9l&V zSS94{Q!%m7LK=qw9)}OqxQ!NVvK||@qKzr|OVE?OjOOzh;hDX!$>s#|`sF~COe?@Kb7v_$N$);o z@v(x%l$y*wp;YVu6E#V&G@@Al1&8Crv_I!5+GgT)wG^zj)T{~?mVKZwfOVSddfrWwkd5f z)_JVjo|@GA+quXs)kvW0l`47GE`(Cn_eroc3)*lOgWW=QfTd>G2KCw+CtvTnoiI_3 z_6t*}V#8lGOSA8zCCnu)>m*gmfkhJB6pF0QW4WSX|Sn8+!D(~)I;no6Y{xvOpYScuEW@k&;PXY5)#6NZFm%BgjZ9cIQ=Abz$RsV7K zLqb)vJMBHu{QB9qE&!h7%2ggFUl?i)=>b zR1Rjf!F57L<0jzc5k4o#0AQGZ_~D1H{d*#e*Q`zz0188s|6Q(?=Dj~Y(5kv*msX1^x4E0Iu@yk;+&Kw?N}BhYz}B5LhFS zg;q3hOEN@I3_gxZY3bpY;`tpa`jvrRctbXOsQ@lnZrGrV1}MOb{0RA8&I&GDHg*j# z*d7KBmXMJ@zbK3zag-wh9b`rxO=3bFbnw%TQJPg4nwSui9EV+^{(iv* znOOP_CH}77_ep2DMNVU755%f@7%ywZaTkJna&}YZe{IqXbFJqBsH+s;h$ z%Z}jjR}d&Ujej*G95Z~ebo;#V6D{QQ_`^%!1ImqL#2<-*Z_!-kXN{Q7vb;c#5Twwf zsAPAK!6L)uW^<2^rQTO&)fE^Kg}5bpm~19{G{ya;M<~cWJ~k7Ao`gbzo|LMCdor?R z>d7e*dY1cx%l8IZ$0C)DaN-!^Gg-Zo;R#PZwN|c+2vE2DFf!Xn^rOLY@AqAKT zlOU*9FE?V;-!l8OhFzbzWItygvTl8Pf%?u|q*=3NM8od&gw(ctb>;uShtKz10ssI2 De!(H( literal 0 HcmV?d00001 diff --git a/assets/inter-roman-latin-ext.0030eebd.woff2 b/assets/inter-roman-latin-ext.0030eebd.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..715bd903b9b14d22a056f10e6d13b8d7e0acce57 GIT binary patch literal 59608 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

+ + + + \ No newline at end of file diff --git a/logo.svg b/logo.svg new file mode 100644 index 00000000..53669542 --- /dev/null +++ b/logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/manifest.webmanifest b/manifest.webmanifest new file mode 100644 index 00000000..15ac156d --- /dev/null +++ b/manifest.webmanifest @@ -0,0 +1 @@ +{"name":"zerdocs","short_name":"zerdocs","start_url":"/zerdocs/","display":"standalone","background_color":"#ffffff","lang":"en","scope":"/zerdocs/","theme_color":"#ffffff","icons":[{"src":"pwa-512x512.png","types":"img/png","sizes":"512x512","purpose":"any"},{"src":"pwa-192x192.png","types":"img/png","sizes":"192x192","purpose":"maskable"}]} diff --git a/pwa-192x192.png b/pwa-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..5b011cbafe874b4951139d7f99058ee752a19c05 GIT binary patch literal 35142 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 KMNUMnLSTZ@`=f>c literal 0 HcmV?d00001 diff --git a/pwa-512x512.png b/pwa-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..80c83313a927931969fcbec3ea8be4fd624e2e6f GIT binary patch literal 220652 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
{4u>2e4}8^1GFylBC*`ck$``fX+tvK0!>nAfQ>F z`w=v)xvI}ug-EF{zi@^@!1_=04qqvdmgZB+>3$Urj_~af$g{$p{=oe#iNvIdv$HFn zDdAc#1H^;AnjvlLIu)24zeH0ux?^s4^f?PyDW6OBzzYm===)g}Sga2#oIa(fYvs=7 zrIx+$0-D#_QpS~0$4g-D%?gYuNT|9WbsC)NLz)VLCRo;q^o2!EMvyKQU4jB3&FiX8 zS29QqmX{4#mb8=N8AeDFwWHOvWLAlO-D|(I_+Ax-Xa(TE5u`EPQzTSbD{2B#zWQ#0 zvPQ6y65;3Tv_*kgffg@F)B1~hat?LYwFJUS%aT{JzpJH4-e^?UGDpZ3S_sUP)&IKRYXOhU2&^U-TKdB6b( zxwX4`UzV}n$K!U`X)#b9goN%3>3lGKtoECMcPV!eh#~9~Kd$(*jdRr`U(_$ooi;K~ z?>AO_)JMJ-eJD$cF`WtP(g`YF`S84&v29UVvrU{E{klcI`aqa-W449OpuZaH5`?2Hz zB~vNyQuBpvBSa^9sVqHR_`={0I8wemwaIudkteN>oyiTtoyzm97Es`XTC7U5_;!Ci z@iA4CNAaNm&SWA2x)LKfSwggFE4YRV|C~;Hpn3`0RjT!y!>R%S^_5uUjO6q04POca zrF%C2Bt4IUmF35uhOrD|h&VY_&Bp~*Vp1J=lr9K7h2b}qf+vG|E`=PWWgg@~tl{ZY zXO}7i@*%^ADVR>cHu_og4*FpV-W_vWnjC(Cwv3@3F>L0_+ja0{)Eo>8`ND&S(70Mx zKel*WSGlkvw-60ITWIX1R?+pRVr}S9VVuA$O(ucq9646y|j1d$hB7 zb0g$}a9s2LQWjSW%pvv?qzdVTCizl%<$BA1j60S0(h{;i!}T^|SEa)MJ7AChCw zpuvEnGISm{$`0UT*gx0D&mE+!%0mv1!287TgN&QzZ$M6^P}QlhbkPwfRkkw=K?O=E z*r401_ge|PXt!V>7_$@&3RsU6Nb%@3D+ApPL_moG*`O7u3+T5apG z?cd{pD(2X3$gsc%lyTv$nD7!=&;tzzU3BOSU=Ayy@}we-y4sG7;IGK&R+(&N+1;vN zgsU(pnJaB{y#OLB2R7i&G3I)GF<4L~mIL$$US_C6YTB2t+`j}$Wn&B%H!dF?dk`P` zz*_}Mo$SO|6Ht|(uyrmD72hq_2HF%=pqM3&n zB`H3fa_hOv5|2)A`c?17SAF^)#hX6z-FS#={yydf8ro0;&$345wmbEy7VhkZPNgy7 zLf>?4WP(P={(f9DZ{oilEC(Q6tnC#6?c$dI&Wrcrx32-hv&rj?|LRZLAqX3<=Z~*` z)dwcM!*MPfSf#-xO41nm(K718UTa(n2yh}`R8w|2K6vHEgE8(dlf35dHrD;S0JOHm z(8Klx3!ynrW$zW=WK6O8v)~NwnT@W_$}CUXomFjZJuLrI6^8>AkvR>hTzq)Ec>j7} z9$a^zg(3|o1`tbTP?z3UV4t==4WMzd0;2K^Az#*O^p^*UEV$O1Z*?`43&*ZTiqsMv z1BiiFS$NGV$863FFkhuQd1&6{xYOxAyS1(w)jUD7B)?hMe(9M0cJdYt^jRu-(7KAw zUH)B`Sp!xd$yfn|0bi(8%|5O~ec-*PFS?#YU=`y>Ma4*UC>qS9t*zjQrj?W75>2Sm zh9cFgOPzV!k&Uo5ltP`$kI{6ZS=g>81duI<6eIdNmjYWu9~`MApkhH)Dx$Vw6cd(x zgtGHPK8pOK^|pjk!Aac+(X0x>4x)^lE6^d^?$_V;$=`yn_@r-vgeU$24>Mq~v`A-G z9u_Wn-(hwk#$f^q!ke8u#T6|Vv<)+QK>t3(Rc5%m3f~GCo;q>zX8OF{bHK_6v@9hO zKNqfW?ya3)BaNpuw>^oEm^9o^zte(sv^(XH*QXk~^{YY6M9X^tvFU2DJ0r#-=G(aH z19Tpm*Rl$nU$3AFFTd&o8%RW_U^&;p>@h8Z&9Ub7MtpLa4eC;$b&N+paiP0>W}lhq z^8BbjH5{r~Oy9P$*~PNxwWt``UcQDO*F|>G>J^PDnQIN@tBO91JyzH_3Mh)Ede7B` zww!t_usR|&9P3G%aTitB<}#ByHdrZT%Pcy@&f$`RTfPL+YzqN1s%1}Auq8z3z+|cd za!dCBP`ldYen}p&LhK?s#I+3^Txg`Yf!y3^x(of+J-zxA%v_efjDh*ie+Za>J?ERHC9?p^c7&+Zz&1)iJg`*YlbuYgs{+FNm z2Upe)mlPxe88Cs!5y(P`);C*Na{|&NULE7DHm%Rw>jY-6;Kc`kT(#XmW5*&kaq{#& z&m`>qUpSuh`T@;x(QYT=s-LyXoiOq~rfeM0%0-rAmtZ?vR8@EBYn-OecHhARX>m=n z(GYp&B_4eCK3Z;KEOlS{oOJRa_X#QhfKJ<&+WY=-&}hLu>F530(0KGB2{f+It~)DL z#VnhCFK-`n-9iqe`uCWNy(`jE0@^whyieZ)1GDDK1apyZ8Eux}<*}W`p+1?MN^6D( zjBA|?8hxr-YqPuNM39bkmICV=1`j$o2U;fWX=9wN$T>&Z)1s;a0R;uY*;Rdk{Jow1 zSTrPMnsz>*7Eugoyt{U9te(6C?-%y)L6x*6az@roWBVI!&v4&Z^HCwB(F){k&T+JX z+X-P_zT=bi;VBD9ZHq#NgQz{5xelC=hS`FQvjUx(kcPGd-jN=pS(skj45Y}XM^hlL z(ni3{^x_qAz>!wpR?HZqa#Es8f;SmQQH7P%mI_hx_&!XO&s$j?izG(hrZCe|umn7S ziVA8{k*q2X$5;5?_xpe4OCP|s_XObH=kk>&5V>}`;=&-@Wp@4A>Du0Jyy(ySTsQ+s zY}YoeJiX6-EF099GA(lU-Ra+hpk<7huLtW_Zt$r6&bzvoaeXfv4QAR)d+Sd*0eFv?Z+z~%zeeTSK!ZOWrV-|{i89@<2U$o zYq+zFt=uZd0&5p#|Cwouz0LPn-HiWn{oc1kBF+Q3oPZ12ZIg3crdbxSG-#p;EPL{& zbK2{4sa=6VbWlLxGMj{F#QM#&uxME;V1~N()H!Vj1<)2l4@ls$Z3uR2r<{c|8pZ^% z9-|BTZR@ul8z_auN+I9;nYWk6g^~cB;5YY+V5ms|gNaJoYR74R=8WBeQz4lD#1q zSFz0dh7JNl5iRVY1t@Fm*sa5ea1`emK-tSqwgYOXVY4Sg?+1_V)gTb&AupB_K**`Z2wciZxZ}YA^3<@oj8ItoVCx?TJ2M7VLBGhAs;C@5+ z{c>?!0btp+l2zX0;ui&le)|* zh51~}fDL0iMP$QdtMQ^E+T(j2N&zdWre+3u`En5rs#!&kWc-Gh78aVvwv(1(#Y@JB zUPBK4Fh(swxRRymunNI7FgAq8oG{yL}CV@aLkKaXUgO#R{>|iuIpgg3+W|quL7-Y zc@L{ietiTC;VZ!=L_Ai)oe$9qY6SpP+6B67-n6hXK;V|6Zysv%a4~7MEe~;gKSv)H zu1Rv|Cpx$?;9smf=2Dh9+jD74H!VP8?z~D89EXIL$2z`s7#-lG>DL`Yj-wE_MXUp% zq{50u8h@RS_i1kB3t48*BEC9BwLb>Fr9-TP0tzr{K00{G6uvkjO*vudeOI65i_?RN zu?BQyr`8%`<(jGW!L$Q)|D_gInAJe`77c_oUFgv_W$5m|1#HV^l|iNlCKT8zE8oXl z)rBQ8`O<7+JnJvX)>(iW(N(6t)8LpN1N3UFMH-onXy;PvA`w*f5>n|1=_8@`mJ;PD4TXcZsu(}%4*^%kdM?%u3IofFa zrVn~XhScTjUVd*JCI4T&f2of-#sRw9{oJp==#{hmcu!>lPCj`bL%%#a!*uY&`RBYw z#e`*P0?V!cAix%S+18uJgE98;@?v>gKOf(D!_R@U3>aXwcfIcC@0Z@-a-9SOFL~xp z)VkW54=&g;!EcpYVD-XG# z+MCq5rMZTMnPt?L&fO(Isz9;Tp!U{<(<0*$Q%k^+7|- zLwZrZO28^L&Kf5MrC~mXz`kYc=pd;;vH(_*NoA^~Ku073Pn|leZ;R05C}c#hNz^5` zKa}9D3J($%=@t9Cjd!2^ub zPcwya4}(9gJGK>&EN2Ql11guJzQkt*0k<6Hy+-!3G5LZHT+-c+zC(dL%^m#t9@5*@ zQP(Xf1eepSw8Hb%D{sCr~@LuCv%XP{&If7{HNYoBPL)9^NF)2X5am%WbB&_0ACGhBg$O1%CnRF8N z>T@@oI^2$rwTAJ1DOqfi%?Y|&a#~zr!El9DH+6;hQbA2FBh|c!5p-rs1{9Z$R&<0o zxf7v<;rKScul#lY`89C(D`9PV-KO}MAdl&Qz0Y>foz{tt9dLb&zG&ll`@jIRv5-Oh zMcb=3u=T*b#l^J`<1;PGKF+yte&zl?&mEoDyUa$rTBDX88{aW?lCOT291ULO7_*`dwfw%OW$2d5P}>u(;j_$s#p-dEs#x9*t76Kpp~M80zIweMocx4rvev@$Q-6D z&FKbKtE7MjXkh-bE!M;rcA^fpbJ8z*nM1weaL zMT?@ySV2YzC|~{32k;f2_$|)?z;|-22_+uaY4w3?K+DCZ&z?w3I%#2!GJv7&~nqM)$56>!HHS+w-jf2*l0lWA;2}vi{y({FxpAo zG}-!BT{^$rt5#^xLE#_eW?D73E7rQaGUC+~@EnBcndC0!C+v{v^Np93(b68FDn$V` zvqKh}JNgW?qh02xN`ur|nRbm4&}=AIUEs2Y$)r+nRlb)KOLi1Mma#myxv>C-wiAhI z^_;?4;)|}3U>faH7|^#mMFAo@py>WCsawT)%8;{ED=e_m8pW;k^a6d|kWCpvD)7;k zM$wlR?e(Fao}PLUeBy!y3i3!XY8yuEz&2=I?e3-i`zil7{i=6CS)e&`P3(3xviC6H zh;eU8ee)#PfM*BTQ@el%O_%q_m{)Bcyy8Xewre{GI!SqPUBCB+G286?h<-a1{^W$> zJoo7HO4ni%ePY3jcsKQ_JW2tRm0@Aqa~Zvef|uYH-Yu*Sx&Cec1f0NmI*Z5m_9Zya zJIa^?jiAW{l{QJ9*%4jZ56kpZj=P-H6Z+Ku1bdTeyE z$pWBW-;k9J*%cYmkYT|--LM6L?Xdbh2NhNogX6QApA@90L9gE`DCJaG+AQbUv;wV@ zQ#K4#R59on6Q@j@{?`~Eo*e^)UDExgm-(0G%yl4fc$+wzq;`0Wjmh9o>+dbG`r~YC z#3o>1VGjZN7nJH*9o!=TCX*?#hK@g!li zL0__j^deC)$buXGrYyMAv<~-SfKO?A&3O>>rjPu`_`1*eeGB|yjxe+exRdB>`+YHC zIL=*>@F-(PbM^d6*aEPJYj99~G>wmM%TRa!!Nu?Dy0c*dw7W0wcSSGGOXo$=l9<+# zxI`XUyL4iW#sMSLi+z!SOaAZnb#`3Uj2RST`ILjwKCe0{sat(I{^uNdNyjd?{k3ck zhNc&tH@$wSD=yCmyfN99r7mlhv&yk&u3*5oc5@@4?4Kp$0v;oW2kE;CkP8{3#>}u< z^dwi(YF-xsl$6tY++t#qMGHTqFWkAawjL<+*mSY!1d9ZV7oEVY-d<0)!Z6G$bK0ty zr`E+CB(-BHMcX66wglrON&rIQ-kw-+(N73a-eK|ux%_r) zZsz_y0K-A4Yy+y_8kHqw1q4~JxORuytu0n2-(ZkA-rgj&6%`4v5VJ=Tcm_CzvfJ#o zw@RAB0kfP}E1^#@$D>JU8zIT^aEIM#`QTfXuc|%4rne2k$_+XGkdCdF--lq2PFAJj z#K#zZ8G*)^U`tgAxEw`;^`wL%tiHE6=p|t@)~Z$=#C`VbzbC)yH-2M$#7pmYc5ZL; zbZ?KAPkmo_?V^c^nHCt6wbni_`|q^JeqZd!Gl*Z!bDA?6Tprz@Oz!#h3L9s?8CS&G znBFw-;y@~J;=R*2c$>4$EAe7?Q|XtZH?--2RGy-DYT9%26}|tbKv&@N7yrhev(+{6 zvbnMPD4;2tXo#FttoAByXIR?O5TChKSxc#^#m-`P`u$OBhs#$PbNEJIy04b?FNCQ% zVy!ozBDfHVec=*1nXjJjn@aFY9vbWZZhaMR0Vu{EHuR^G z52jdon{&0US|!=|Jxr}n^cyd#U1?S{NDe$!ti@zA;{+yyk%&tGIx+keUNsLX*aaUKLpmqY+WB-AFq+=aj_?VLweDpFlwnRZ zapF|~rwYhEw%$7pamfy~+1KTbGOs$GY1je1!FV(~4Rsdzb$fM_Q(q!kUatJGWKppv zVEd-*uj$FprNN!`{Ih@YmPwBcHLlYVPG%2?T} zoIeFi0KXGsC)as{mb{ex$nGPX?VQmADG&rXFQE0b-RI^mLvA5`%&>cY8hAJ(Q=t}Q zb_kIKOO97yUDW`V$y03_Gzj`PRF9e{l|CXEY|tSG*L$c(KSpA77vqn4s;ZExiqun; z>%VBHUYZhZ_#meMH&j*~WULuG$H=O;ebTqAlm49H!l}DX_=Mzyjd^}i;ul@}{f9Be z9%RS}vI7POxv+Wr0tVpHMB{2=<1at&V6C}ijW{#V7yXC%sx4miUS;i&%! zRLf=qteTfY4OYDs{n?xPN~CVz^K)*rae z_!dWy`Sy-#-|i+bb|}U!x7RBl%hr5BX4|R3g*fzJf4j0=@RyKTIC>>k5M+ceK6M(m=li(voyl^l|sm zpG*FD>&JdKS|fH#=GensoSU#^%x;$e@At8{X@_Qom`MkGB5>`Hct(bD^|Fc0DUZ2f z^EiEbwIi=4$!)H@nEw%RdHw#xuk4|&UXQN(uxSJP*t|a0dLh^hoMcAO7=M9|!8oeq zS>t7P_P8v79(w~+Kp@&5JKGk~9JAeL(Oj85?H|BMu*?yQFIO;GCRF>sRK|pBqCizK+z=*^3KTL{wajvPpE|@D;A7*MQ zafbyy@Qi#~65q!BcxX>Okwkr{%BAy^JJm&B+e24h;D_%3uZ^VZSE;!N+{~yM+^vf} zpKT9eC8a^YY8fj>X5bal{nit$v#KH`=M_oB#90N1pnT6dyQ=BU;#C4#-T7FqaG@8L zoh3>dw2uJJ;D2zJi&9Odqk`RrvDTQXI*bt( zO-D9PXstDbvH*^rv;?%k);lXzrt>V^EIgRtTI^wr)!KdAEd78$um1dFPQB)+AZtYe zUO14tu>BgQwl7xpk#Ya)eZTKB{s7+kYYqI3==nNbxWqJhRC-x6y6%>(u_LU_Iq<2} z&U+^7w7K|`7n7cdPFxbV)8K2_7rQkZ0mK+CFNV!amYzt-2V@Noy!F9Glk=9JrPMAj zOg;&$tU|v1YlN)cGl?*TR2#$H8g`cXJt>3Cl%2@FkM*o4}zY{s?t2B<9**8 zy6Z${U(H&{P1#OLzHpH+qZf;hwLEQk>&)vdkWT_hXd7eEp2PkDW}MXLNF6$FftNIh%?+;P1oEu|6q*=%7Cdq39DSDt&QAI7K?fn ziw|2+r%{6aI)~25vzAa1nF&>UV5XDp&U8rAfL}CcWo9KWA%~Wn$Db(P``Ka3QjD%V zP)A&^?(;u+MKjF#tBo8d?^ma+Awo;9xq3XZBh2hHN6nYyN@vF*mfg}0x-6hvf2l5D z2W+6AgNF#SVh0zYot$)c$~D!E)h8+(v5bG|cG4AO0k5*{)y;wx8oFu;40OVba+y0h zMP4mgFbJs8MM?)jRlrI{mZ)5!4jFB04XA36U5ZNA;)-NKQO+{2SHJZ0c|Ym@*{^>G z^y)R3q_=x{bv=!$z$rtwY`n@7-4^U)pPRq)6%IuH-tYNhu3oWye$?&-FAoUf1!L#- zn@#csB;=#{aIw6^3Ap#=ot!b`(9Z3A43~-Xcvq4^(EM0-o?TLXHua1dRIpS=J2GDe zX*d-k7%)^?7zz?Igiry?xYpB0S#X>BtC;uuHv&X9$b$9{+5hqhkR$B#3e0o?-xNsG zcdu$N>kI>y!(n3v5>K1`r>(oWD`!(fF%4s=LMC=F^yJq`muIa-zW{yFK?iBJPDrl` z!p$f<$euEU0d=J-?Z+wOq)<$Q+siEsiQeT~azOO^a8QN?M&mjcd914wVk5t{Cqz%X z(iuR}O_4p>uv?H-{*JBej9K{F@uXsq2cbX*W}6LcKKkf))79rdqI9E!`C|Aj$No_2 z{|xE;A<%XzWvhBAgUgVu1xC^`$? z0nt#O*U!pCDlmvDhIyb6+qeoqWaZJ6i4zTlwJyu_DY~?@Kk82#FN$ITzRn<&%js$f z^_xM|I?(6AmpBzxqZyASvcjtM10VhJd+_z2{d?n0zw$?*jL_wuXb^CaxkRo6BDQOg zTzaqsqmb^mjne|}>u&L`6eqyhX?yg_heHguKIr?5bADt3MM5+s9TOh|m~7Z`m?=;&wxi zKg{2BsCCJtf^kk{tj|!c{rvhb6^M?i(~^$`teb8sfodki(2Xqn^Kh*~3g>Z)sRE+r zZ)gnZGrAJifgL>PM8|3OZR*Sdfou}UuBF;!_R;f64mxr~7Zlk7sIKEdbJ587PXn)= z9c>{>Eo=smBj?%`8o;6%uDRG&bJaS`C7MbEMxYQjL{_9v2PwyaDr~hlQD&jEsVWdwkNI8!ewi0ELydY{=y`no&#f6o5`Z~Dl0 z556?FWQ!P5^4}4&z46{1)9Ez;$>xo1e1EU8fkBtcYm9$2@AliLbCO2pw)NZJ=L^Q4 z9?a%4dWVKOPw-%Zov${>Df{<%w(+IoHq@oeeZU9uJf_NR{qzvrhO?4CbunR1AnSA& zYQvT{7o9o4E^Ay=n-CBuMj3JvoOCkfMbk3=VqZ8<1}i3@J8*+P&HhS)dY`x8T0TOR zi!rWMK$gdB`!Ap-eF|oZ38907?aQXn5(N1W{DnP{kYvk@u7}Dk)5EV;BY1CVV;Tdgu%U;XyiqHlNPK54xgi@Ek4Z^rZ(@Ca)mj zxTXq+RRB_nBOK7$Q)O=fxjyc^A3h&BD{4ja!R$pxk|xTL2E ziy7VVSy8b14(Ao5tK5$QF|ZhuBPcNdp(En6CFPXT+yTrsmtU$(DHSk5#~_x9rtvU# zAp|TIBxhQgmyz9Rd)=$w6JPfX{;zxay_m1S$@|UB4T!6IwfNZk=Qe(Bb8T~HUbIUa zE>GlL_p$N!DR=VnYP#&-dq2lte~(w7N8>)YuDJr2eCn*O$H^eCP(C_9&&6=;~EeC2lng0jXuXTC?h~1yUS9zUU|9z{cU(%c!FxEd&e>?^xJz&)a+FfX^R5;t6E#@WxpuVp@)^>vDgf8f58|G&V z`BrR&I{PvEYIa6pT~$aQjV^~599wvDxN@f!$alUeMH+kQ-g?1mG@kzMoTS-n4ccXL$B)zMWsEYq4F&q;*_3K0PE< z9^S6)V_(s;kN;qJ{m#e3Uv-~+yUt$4&tY)2q51swhID7&&*X>t_L&$q>SAkoq5}|~ za+U6_mUz>fYtqTS;DSsgTEvJ(gd@k_R z)naYr?O3Q%o#bpPv9mICiK|c!436x4!4V{wFNjeZcO#4zVa?1d z0kCdwYp1G&WS}*uUu=fZ+YUVpD>+Wd!Kr3}(~nRM2wr)yjKAGg_8PRkvSbq`hWec* zf__{xRRd10p%D{I=37;8uQKs#*npd=5Pt z;t0v%6Y`qqS*r`OAgl}@5(}N+G9^_KYK7!y6uq^Fjs=>jz^2ADh)G3;}1RdiZDx^Ux)1)r%R|fCC zEsci+V%W6KUtR6z-g8cBYYKv^1D}$v3O0gq%Kmb_A@6f=7FA6Mw@YUDYGojn)n}e5 zW7w4wZ0&xk-0xX)4j-c-Z=PhaS1`&bB7u%2?U(VLRRNCSHz<@;&{<e<&@#@B?aW?t7;ZhHRwjyibk9JR9KZ_w)(G6o2Ksb+*!&!AEkhGy z)f`w7VOmW3>V0t6##g+q^KG*@IxMJJ4FY7$(fvb_HEF6<#5BvCtWL2hHBVO~mRa2f zWm$%kmf>gfuGopuJU8u*`W)|cnMc0JQ8Fctqr z?VUJHQ%bl4$%ziLRBACh4TH{Y4!^&T9h0y}8NBAQg~mqP8St7`T&;PV3V6)psomCY zyJn_&J^plfW8UN5PlCDGIpISjI(n@wT_a<95=hYWYVD5_YS7ip-<@1x8ML~)N88GJeCnWt@7X$1Gg!`ZK zeJ=aQDf1r=z?2Ns2h87_!x&xFE_>`9oc(9anWjvEYe034iwhczPXo;3;=Nzn=L)-i z)h6e z)bNZN8(N^zH|hAGWPxs42m3^a<_s$=)Lg;m>Xgkw09Zby+7Q@fUA0A^zJi_*IJLTk z)?I;0$_I)WX-NqLG8NoIm5k-*z-`N?3M{nIV7DX)`2Q7?qQVuJe8j)={^L=<*S+dJXjzFjh5Q{=nVZxL_b&Xa?fYr6vCt=(yW zL7;Wr7lGE{I4RfG9v7c+LBj=&gRTz~!1HQsV0Ru5$$FTL?~c|TUl-Ggw-CsKD(Z$^^ zp2RjV(+33dx7trvm&A#%;$E1_g#jOW(di0YPGbV3zLM5P0%Lw594#}PqxaAC1x3Ls zL6ULo*yE(`6;MA_gY=A9ORVSq=|mYvcM~4Yxqo{}V451eO7V4Rr*jpS4$#M`1XIpg z&a1d==Pk4pTN&g8bLc~rc81NzSN(?nwEmp0ty)QSH(`YR$~li{qa4HJ z;$xnCEY6EbljoyXy!eh1?UtM}?(9UbGqUx!%v&@W%v~DH7Cr|MUhXM$Q0!PXawlicba>>~f`RnN4x|L4HX> zXZcWH?TI%s8EqD%(1lw7W0j8KHwaq68iS9?@QrM$fUd4q*?pR6*x3lqr_y%|`UrlW z%p<4M+MG}NRf4d#UziZqEDHL}eR-fE9W|*+{2@-GQ)O)y)Hr)ZjCO265)!;j_0_xOC#T~VQ4Q!ethYDyU{@s+A@5b9J=~L8u7of>Nlyk`T^gT;(LuppQBL{k zBnB@jtJqC?DtSxTnnh>0AWesm3c%)50p!gD&TRkK>m}Yr=|~{v*Xcr_Z3%940Ob&0 z^a|S|Z3oLVjiE1tJL(D458BQ->0a9R#2AfQ4~XdZeoxwW4%2CP2Fp;a2TS8Rt82TH zD6S7*WX`r8p8>ZMw9seX4Mpc1+qMW~@MJuK zotDE%hApLD_q(@xs=(Qu9CvN8L~n)Yr2ZPgxg8xN@>>G6+jx)Gvd==$Ab3XN*85Pa z3IT#a=7?Y!;3dBN6aEyw^o@VM*)Pc@##)97<<`df2t3k-cG-Ri*T;Eq=kd$tBN+W# zz4Dc(A5(1W+1M~ZJ+>*t*1$tj_Uc7knK3S|<;6Hg^JM^(+gOiYFXC%lcg+`kPS+1$ zfP1AkVQ}Y7wHL}D)%Jl?CD60$H~};*4p;V1Q>`*9dzarXP{R5?ftB@Fi65Ia!``gD zV?Ih|>(cx;1GuoqMLPkCceh2Y<%4-6K?>dUJ;Bd(_NmtgRgYeknirTj2zi- zQKfVzy=2btpxV@LXg-(6s4^tyad4vtx8NqF{Wqhz11)9!p1CXe+yduXV1p~=np)o) z=a%VDyXCIeH^`%hMosb1^~~%r>Ibm8lDgM|!%Zz$;F%SFnWlsjR>4WRB~SL3e!s-F zK^E4Q+d(Hm28;?A^v3$C;MIb;C!_!?W-NuT8bM{I@G^b4)%ntIOor@k$nVOv36WdKiq90$Rk029DFvu{ZMDc^bv}@mkYX8 z-3=~^N-S z{Bqz$+siM1058Al0|!07{7bKm4}Iu0kcZiV57Hpe1wA9(aBt0M-7YiI-h8h?N16y% zrmVVWgW1s6=**q-uX(FqSz2u;uxQX+VsJQ?x2U-=%q;Wh8V$G!Gl_>|ZE06yv?Ui6fN z(`w;Rj2$9!y9mR$C)GVId5aC^_(<=&r}4{ShZ&KsSC<>2ly z55FbOGSTe!i8sCR2k7RZxe*DM33_to~ zU#7VTtjo`=ivxU;nkIqt!tIw**)Xao2Rral_`XvT-X64Vu`{l+|8Q6HO_-`UC0Q z9@LZqSCDL#XVzi9=D*IHveR{MOZ+`p);As7ybOlpZ6c)Bc1`SUuG2#UYVPfnv1&p%xgaU z4jB7;Z;SojwCcy5fK!%UulIi7)A1w!^2_k|-}AfkeZTm|@cY#5@pQ<#lOp^1-p9T6 z-T36^K;Soj%6B{m1MfY9=@mVv*DLdTydLr95zimWWdotWLl&L~*n#b;)0JGjDIG-& zoBXE#>PO_9aP}z<<`e95qmz9ITHBh>nOk^wjn6xBqD4cWzVE=nGo{_%xcz%JCwF0i zEkRN2G6!Bhbd@4%_*Xw?`JeMy-;U4y?C*Ha_TP^YU`bZ>-tRsC{?G?sgCBbi1m5|B zUyl!b;7v`R2T?cju#%BmxuBK`9b8k40-J43A@zy14!OP7DecvV`^70e^bar17 zATqhG+L$wdY7JLK$;T^2Vl~9qh6+l3p4QDA?Kmc}dgv;)WGLJ z*_uLgY`Qvp-t*7b{3S~ziyZ}J1*Ot$RRn6-wst>9V1igtD^y`PJJ?$8{nyRQbyniH zD#Myh`jg}cDzK>gp5YJwWVEQQ9E2(wCAfhnp{)lGh*X3G3q2B-DhG9+6G6XQbKl7Hui#-ipsyPgtN_Sfa<%Fe%hy36ChIimMfAV+W zlVAS>z(XDl!XC828K^hKJ+T6~SoeeJE_oYxF^};ALUB!m_oD;ghyAln@J)a5UF{@+ zk-{s^B{NKvuWua=>R@-IV+7O+_~ErTx$StnYaK`SzpK|5$ErEAil3;+^mO`sYC48_HLhlhPJMQ#AM=%{O*q zN&BiF0Xck)S%=42KIYg8lC0v<@8Rv#&zCLvtUFH&b%KFL`qqi{!<3>0o)p~xWM7Kb zV>%@uonvq7ZvdAJBuVTtQw6AHb*eXOjk?B0Daqks?5SU4tPJfz_`B+xgZ{X%U z0xg31mT|*?c5J5QUP6zd!A=WlY~`w;&;T9#R>t%_6C~#s_mJ_FNv)ecVLa0}b(Z4S{>qB-|gPJ^cUUvQWWWNtzr)t52Yp4KVv;VQz zUIa7ilrJipX#XgKlyi)#VVdJa*KR=55!g#F%yOJO%t|=sz0AJ(3lVG|5R!403b+O0$b(i(AQ}GJTXHR0|;X{ zI}v8b#m!^isF&H8xqwb;Q`j0!0oq1N4OU&FfIEvFgUJ+x1tNzkBsEjp6S@ZY=^|INGqF#hZhemj2jIqT0~&HSGK&(~d(l^4s=&k$ZKQ|?RK2eLM~P2lp14Q$x1&2^i{-^Bd5&-3tQG>mcV zS_}nTC1!$v*F^2{;W8TYjx{E~{`Yol!Fpe4KeYEj*Q~6g)@f>e16%Td+B#P)+fLit zy)8Er+gwT*6KC^J4=T!YxJbFAobbOkYJs~foCSNbQAT|fcT+q z_kZ-b;qpz=M@h&5+4WKFR!Fw~!ek*zlrGkMN3y!U1P9RLC}#NO{CFsi6O+5s9aG73 zmU>!08`!)}RRB1%0tsh*6)r{)CRO#5qk9pv*+7?uX415Iw$q*o= zXbGf8ydaSVYc(y4lju7|r22%F$#?>%g9%w^V3ZOYgL)AiR4WLo^{j4r9QgZ^H-7uc z*&v;n+s(XkC|p5qZ34J3Z_P1pTD?1tdF}Sw?Q%VcC9z z1nX$Ixh4A3KD@;MMAP#GT({Q})V{|<1602pa2Q$uIb4K1|K!^-|69J`?eW$x{ARrJ zD>gg3QbJtn-m6}IKYr)${MvgEu)OC@nb+VgidXAnpJH2D%F;T@Dgji;8`YeH`^d4L#=Z%Ku+VTT0|S7|yH zFg+moX_(NZ2d;n37cqgUf{bKI=2UV9ZRa_d3HnlW9lb;6Or%d1}fe*8~<*Vo`RukEcYf|D;{^v=OR_<0N%58SGPx$6qCD1PyE zd>3%6y7=<0k#h|eHzv|etqDTu11MAHJ-gSf>1RUg_qmpD`E^^R{*ed5sfvRFxGswBONMgRNZ+PPxZ};&r%MH!BrM>j#l>* z|6lbR|A@_>?ace4y<%KjI2RY~@ZcK9_;A`ic-@-|@Tt@BnB?cz{V~3`|K0Dx_x;3I z`|PdDTXMl*NAR2VEmC&`oB2qWM~O#4T+Crc|o={!oGxMx6d zFZ;js3*SEZHi>=kKBro^P4OE0Y-7IaRqw~!e#h70<(J>jQ(@%yXzMa+K#w|ilp}K; zYEvNGMJFPjRbbY4_Lr|iJ4?Bu*v8x4fTy8Ft(sB;yiM2B%( zkXb$jEr(;Q{Q#u8aLx7^#?!^pjuo% z#66E*nZ0*~zKc$*7G(09{YqN`fJJa<&6TUIO^0r&xk4HfbwajzvhFvW6(EHIF9)Uj z&+mKlH{f+Izt>rS_6Ymye2oTt**0I$^|H@Hgqi*0;zxnN*5~=>@4feT;qCv=@4`=g z;LWZFkW3SupEc>}!~1wmPqn5Fgtv*M6$BUQuc~zcYeO8 z3h=_$?jn7ByOjG->Fd6@??Y{4nX&B4of96f<%3fhyfPbyT)1{1XZPvTmxejNZ2diKAvjAW4MQ=yKOZUwy+JLVOy^fBc(x)%0i0ELfcs0xL z9owB(kzqinK8L<|l{+be(EBmRh}62zWJl>;@v0w{EJ6}y{}^nHUNlPuXAdx09&IM+ z0c@%=(f75U4pf|%tMAkHkbDI>(Jpn}era{oenRmU3(jteey~c_{oG^1fsom+Pgh*b zc5mW!PJIn9+d9TBQ){7yN*o{#Q=3-dJfQMz2NyQ&2n1rXe065%9W%;V^jDk}>elpU zg}iGK9asc-234|)%I-z-5G?i}Arl?)GO{*rSyWM&L4MRzonQW3_J7l_`VpLY&~u$% zd3`A^-iM8|150deeg44pD{(=VnMc=pf^{28EQu@930N{E4-}-6ae7z>;PbpzD>Pkj-`w84}YhmrM8FtJ*x^|jJXOOrRP)^D*7-9@4Th;}yFTf+AIe5TDRy@*Ts>Qct<{13i*caqZklYynb7f+|6 z>-{#_tdi>WIiLF-`1$w03IFJae=n;5qbHC9wCJm{568CofbuEsz_wrI^ffX=ugZdx z1Hh^-nqkRf1H$s@?R)72V%WWWLbhzk|EAmKW$P7iWXk^g`uftQWKo9{bcrIIMouXC z)Yxmh8`8F^Q%o~GTC~}rK9{Ua&MO*SDL&fruK^y}q*#_#kINdWlc1G7G5eI~JwS@K zc8s~&!CuQqgC*?BW>+O0W2=lodREC^3da_ScI+u-$Q(;I2M%)*sXi)IDWY8WwC}zm zR?4n2{q#K>Y1yhIglYf`-@q!u8aXn$wB5C^rl}niSE~RG7I&A+NqVTz*E7H6W4{|; z@ri%h_&$VyljF(l{dQZTJ9SOCF`oLR{p`U&Ui4|VJL%r$ynl<|xBk#~R{C{-lk@9J58NcP!JpeargOnE1p^{v zKi40kzmox0KNj7sh&*QzkA4W&k1a!OA&SQVfo8jFA#z!mMsy{9fcJFBal zOvNEdR+q7{^lzYdYx}TO2>?EW?;P-8LAIr>Te);eiq>l=r_xRy=xV_8%*P+bp*>%% zk6bD%Sh83ZhhW|w3h-<{q%4`Gz8O^=UuHBMd#wnhw*m;o$VDfODn!aLe^#3yO*!*J zzz>BiT0Z*a_r%*i;hS-C=4qGYTp>TerW$<11H{I^{l2az28e0-SB@;V!FH#Vm;iGB zHorIHTi^K|dH)*UVw$L?bym-ITip8LE+ZYw$WX)Pu5s(hizWHq_m_%lOJ!7qD>Ck4!9xdrIUz$e+Ggc@|*ezqX(F)fx}S))F# zjR1my!O2eg_k!a_89AB58Q1lD-Co6$#$mNR}5&TL?!OGs*tJy2OSpo5J?ana!juzI91Itj2# z3RM$wMIa0x+zc|Wq|o3_Hu1XZ>(P5Qp(xt|J;hpt1~COzwui*4{kjGO-(%@$+amfZ zKiAZZ@6sKw*?4%LGA2sjIr&7$OW)&Ylm4pT@JH73{+k4*)7Tu#@B@h*6WXDeBN>*6 z?Q?Db^vKB!d0Y_#SK7b#lV6EH`<(gz>@U8lEj{ftcOTp<-sG6FqwcC9Wo^cEe`075!U;X=kyq-|7Wl9%vTd(~--5bPMJ2WpdFUEps zyB-6$1n)D!*h+h+VO}`y=~m)tW^jQ5Q{rs})|mp4V+`WT;R4pG3&?A#CtRE(K!c5- zg^qiayO-%JvtQ9jIpZ0a@LG)Z!h+ADbI9e)ha>xc&3k%&HL9O|I}BF=nP2w%vXhJP z_t$Fs`d{-S_=2~*9Se0riF;?9U6Uje#23(~S^}6(k%3tb2MrzwS>=|>tg*htMlwon zIfVKL$Bzuns|0BAkbxZOWWGLRVOjGCK0>M-3MR7VGjOl$J6Yvm6^bkx?y|O%o-!Pw z#TSA42x^wDGic~LDgyL!Dp>J~1%IBZroEu+xUzqd%U%_{*$S>j znj_l5x??QcSmWLb^g@0y%@0-(&|4Hxh8VVP=Tn9sNtY8g-Tn06@Lez_*tR{s^hPyzB>B40IFq6>U4zVwBm(3r2kP>Q^9-CYMffjyAt z(=A1aElZB)RIR_Rc` zt}b@?1uOn&_F&y(L6Fo20<)zL*<+@xSl|U!N2=QK{NMew|0?~X!D2BP<8=uz`=x{} z9nLImhqw}71_K!VE??nuJO-irVZV3$ldo49zJs^Us2b4Cy||TCQ3|iq_hOIB^e8^Ay^jq=$Kl(MmK%@Gd_OpAj+&-W9R_{-s;Pz3KT`RWKSlKw`y!HDu4X zEMq1u=GF6d)^UO9&~@}0v&Jnz>8eM6)R~oVov3xh7BuXx7^Q91e*DS#WT0VZ1}d}= zzOeXRGU{h57xAriC70q;G^DLF03x&jzB42-A_|mZGx9Pf+hZW;t#Jyqhfk`k%F1Cm zG`IHdj>u#I zs!*UWeejoGd+hiBo%>1u%r0~#82M9iQ)7lg$THo81w(c)COVq4IhS-(fRLEgnMEoc zK58E@%OjAsbvUO2>!m9AFaYNc>{^zcx`^^PwM%8)Zs9g{Tm$|K2~;D zbapwn^(z&CtYFXe0oZb6n-|QI;vt2a_ug0iEEw}INAX|uQKFhIopQ?(jmT$J~4c7Yi)B?G|g)Yf^S$rI}i;5Uqh19o% z<7TtMj#^s`vew;IB4m{(QVPv1ZWv+uCINM0LB+ECA-Hl}aK|WzHJICX$(-Pt*0?-? zLN`LH6P@iGhyK>{{zD{i?;CSYT$hr!HmBFcz1s^wryXx!Cz$L(Ltv2cz7M_$-}*z} ze*Z&0(Jt5=Z1Ew+02sMOw8JA5Zw@e<`}9krnjv|w1AYbMKE|o^cnq7Sr_`mc2HgXj zzwwX$NNHb8dd66fWU*g2i+Ev|7s=M!U9`^!ms2~_+8v^+ zI`yRL0uAoejA-3ZEg6_##Vl@nOiS2ceynzq<81%8)EOiTAQa>HE369j#y9-Hi}{w@ zy5~UCjO7M$UelP_h__!qRiM`OPx|$L6QA_!{wBEQqub39HZ){~>)FG|p30}|Hz`Px;04g;CF@BABnLB7lzMMwhkrjzk7vh0(v1 zHqg0)&I)LQAt&~rr^~BKI$WMCLMRy8bn1TdslYC`L*}(-pYTF9YjoL}yMSNDXYp0t z$f3OMKC@507AVy7A@bVH#s(O2rhb(GSHMuGQPVPP8E#0qvy=E@EY_M=@F5Tf#mu5T zp(j^W*DDg7D~d;pt~SF2qp$Q8gt8r53uj(T%ov%E)^z-Jzx&?**+cBFIA6-sn}550 ziR;)Q_pZ6M&+GAy_qo9T2frQfegCJUG_~qT(E(PLd@C?4>)ZoNI`U>}$;C{joLQJ< zmC5klI@?iIe3Mer{)t_OK_`{I13@i*xsB)B|J^_R%J>&Q`{~BBjhPp0zvdV4LU7j9 zILjw5esn(#B>35B%?AS-JttR;^JHNFS>^UIeDwDM3~<<-DrLAnvT{1&!xBtxYi{0! zZ8JdjAC;_TiCj(StIfwmFDV%WFi_}u7x)$Q8S6gg*ZhdBE6?_GY2PKM_Q|-kuRzOf zEn(`Mhd6x!nEn}G`elFkcshVA&FGSH*uDuHR5C~I)M2!;YSBlZzN#{e)uaa-qX|8z z;BC1_U4wjR1>(toZ(|RoyBq{%&+XpYYEqy$3qRG5G$8csW0$1FXL68yVf8_Bg9j2d z7lPt=vb8_W(+A{snp^E{3F2`Q7rPKZ&-WB2aQid1a<^%DCmpesQq+FgYSP>Gs_PH& zpn<#hZzFOXnhP(uW$n14R4AN{vs|*=#*v*(JWBLqgcu4yrvW}Wu#|=&z*>!4lHKXb z5-HTMWG$>jxbnQ>XUy{jwxt2O{kNstjm6O6gYF$TEob!2Edh{pi?JGL)Vam>75d}_CgAqwy<9eHPBHEQ~W5Oq+n zPLR-G*qr`?GG$PeOcnif)U~no{PU3?`5v5j!VvJ7sdCIz!}AGWZfEV;&P#zO^^SXGqHiUQi(R;;qX4a&Z& z^g=C35d5;hJHi5ja{du4568V67wyMLQzR|`p#Wyh8lq=?PT1K3j!_|inRaP}wA=y# z$oc1rSHemz!Ez@YW-6}gEVt)+{_o2_;ZMy+{`@rz98)=6U>J*+-4B27?WrW`Z4wjg zx&AnVL2+?jU(86RShTmy?5NDq~RHwiD@lWh~_-EieX<*Xv15hD&n& z)XZUa2|h719!)Hrta*OoU%eGS`wRA1AWR1P4>n!{L(ia@O*W?ivE9QQ>*2MbK-=7L zLFnXE|GeN;&ci`CI_Nce+WrIn9sHFv<=RswP~39cTMdVD&4a4+n8mH%dK3|KTCfss z4M~7WjG(DmJp|Y~I0lJ)`Q`Udd7k*Vzu&KUKsK#F*JyXtC0B^t=gT=n{r;q1_cxBM zfOavS_e;-gv9g!ehLS^Fnk2DjS+{b8j1(3aM~aX&W=n2Cc{|CvA7U?+ z7`CS)9ZM=!x#e0`D<*@P$Tns)LewrmvAr@@OLj&ksR4`ITL(w&h(K`SXzdQHhM zB3Ysn+cVX=CqjPo%m2Je|ComB{$oU?yq71t*L7?wm4ve$hx?wr51oc*hXe_yN!Ouv z@B76!K7;?CKmM>!gv5ze11T@h`)wlKiXF8lk5 zf5eBgE(*Al&NnTbh~p^<0$O=i%eDHP4F_p3td*E^ z*oy@Bx7vQ*XloOrYOE20a>&lK(<=y_068|oPVl!Ql&N)p=~dL$2I}#@B8KPVQt(h! z3Rop7`e~@>uqTEYRzPs);nSkGz)S$q#Te;QmAki+H6xlhWk~k}1}v@Le{?VgVI`RC zNF^$=ZYLSSzK|yg(VMlMAWFli*6()2QT*w0A|wAbmXwj=K0sdWmy(3GNsdE`AP@km zXi%!IeRU(NN>J-WugjEz(J8%!IhArScUph{XMb(4b$Ch4_q+ezFk|+2Y~3@sB>|71#t$I-~3R$7?5hH7%VROYADMW*>~=_2hj`$yBQObG7dauP{Uy ztGEq76V($3(d+Gbf67!Cqy*mbYyS#f_gn$k9LmXm43J1tmz%+orCi5Y93H>oLEl$+kmC={=e`hfB4oKg;5>bEIAC-TTyS}0i^{LPZ2|B>d`GJ$LgQjGb=DJbx8WRkpUd# z=jcq*#_CdG(MaUDKMwdW-v4If&CcVU-~O{R_C@@6aJZ7yi)6ix@eq*mf{YDNcJ)dh zuCi`<=(7KS9Q;A4fyJ3aQ3H9lRLhnu8w~I7o=i5;6#_m+m0B0S<~9M=F~h<^GqUC0 zQ-Q*oOPEHROlGsk7$5qj*Ur`KB5AU*IkD}P8^1TZ_up4y&#U)&Qk&2G{BOq_KK}2n z%yfA?5ncQJOjE%R(tlL|C?`x?%ihLWW|sMozQkqlT}G&Y5{x;jJ@sYL7C`Qro6$an z_Ae66)r4PIdYM8KI8aM8C6Yj=9mE0GZ3d#EvDQ)Ka(ywj5?nu;G#i(?c|6^u(%1s` zZqKpIU4_7Hee6;kxU&$pASYTq4u)-&1gbzY=@^ZGxtJ3WbNlpt4yVIQCUj1nX$F+= zh<0W9vw~5pWzbVpmLTd&U`D21Fx3@M$@!ZnPM`0QrKGQU>=w7S5V zzvJ_jj5q$i=yfTp&9mo+F=alOwjILtG;uKr{aTLTc=-|@gaQv_9kec7F}0V=th!K6 z`yMit&wxG$HwH!BAwli{nBzr2*d#y0!)~B`SCy)qbft$&MY%_;i4-J!=tHkDw&Y{+ z#|7_mvh>7r=e@@&z-I2dO}k!f1U-NL;@|SWTi0(E;Bp#fVd+za*2`c>Sydn$I~csJ zvUZ4^vYXfdt>%xD0VwV`{;7=F197g~Chr(jS5g7$1n9Bm@-PYXT9ha(?d|WND6*%| z4_1pQh_K+HS#@iy^gmKmLDM9N3yZY#Gi$P^CUOBM@LS}>1NvvL-4PJAFR zEI6^9uk5u2VrUWz9{p_i8hP@)!KcdDS#6$YdD}Di-?RTD$7A;f&iwt-X3#M#|HXa( zZC~zSdO}^gKMVhz|J^sQ1AkGPh9$GCY82c!M^I-hhAG9ebRvAH5W_YLnmhKd;Lhs` z${(_wRn1*0#ImF$p2Qr$!j}##ycwt0m0a=#7joK$+0T4W#^nIOIo?Cx zQj2~5dHu)yzww!$_w53go)afsW+2|WpB)ree!3pI}p zeRkj|Hf5Y>RKN%WR~|lJ#XNsHAUV%MjmTjP0^qQKsMenJ8p6PG7~I?E@?AGcXjisx z#z!iA$XIGiCPzh5B6{Mxr&3>MC}K0^I`kB(7Jy||Fa=X!RZA^B%ZlbLl$cH|eNUH! zRta}8#T=`i3&&J$jut#gLATq&1^1LwdwwXdAs|SLBFxc5gUAY0n7!-U7U0knGJ+1B zlEF%Lxhqe&%syV}xO3zF%>P?{?RWJ$??2gTM3|{EMISZGg=V_xJ9!#q*@ip8I&au-_Ldq4ke` z+46JYl2*;XD}&MC!D_@HpabsS@1(=a-GL?deF?OaXLO`%y5WckK;@N8$BG6AYvl=~ zuNu@D6U*qz{)K4;0_J5!8U4&%b#BI|di#O*zp44UgR%d%Wwrh9FP8y%Z}xs6rc>}a zba6~-@&-Qti~l5Ee$~&bvw@>?wfrCT-lwUGPEZZq{yBREV?AyHIqYBSvaFVSd&jsH zT%I)wBjSJcSzmo+={Q^S<`fd=`@^{NdKk>x*a2g|=JQa)_P)=b|Ju9%2!8B+ zUu<-S3?y@-t@CRJL!*Eiof*_Yi;|54(V)D>VE_RXAU$!3-Q*HZ~9>m753@(UWG zXn#^g1L1$38Y~IhrTbX-zY(yD&FQ$5%g*1}I=DRc%+TL!d=eB~JSyPs&+5QyxF#&~ ztQ#Is3`k^7(1Z7b^~d+{cFuN)|$=fZ6M0!mgzIF(!iNz z)>c4txfkYK$t%hHBD?<;I^g-DsI4PD--#BzO5;DS|q0_xKa$mp~)Ht6qLT zKJSbF58Wy37zdM?>X1VZX#MeM=hIbe&%Bo@@witRR1hB3Kli06I8bR`?ec8@Yrg2J z#7HQ4IQX>jpg?vD2$(oTZnWi~Fw9BCv}@|66f7~y7)pLZbN~!WLo<{}*WUst{Uwn1 zLQm~SCs^S@UB zoDna6nX`?HTP09^&Wkp?6WX&w_c6QG3dpVR^UwXS`u&}M`n4#BdE7np!F8aynVlU% zT2m+cY7cgs{-#p>(LP5%VC)U6Ujun^wz^Kx_wybKbbIO%7#!+&gNn%OdO**vmveSy zyMHGDEE1VA*%s-3JnVXIj(#|f4JdXUz$R;P0}pJ*9e~R|wsHLal_CPCU?Pn-<^q^5 ztluok<0$!>v*sYSdInu-YcYz_7b(w^a{4u)*lZ+)?|o3F=a7cE|ZviZH=#{VPXoq7kK>2?QL%3Lp=S=&-*rf+?&3?YBTg{3f|bq zg@US_ta|eO{jJ6Ad_h`uNK5cQ%gC(C?oub(eJHB*t(owlY?W>Q3-UU^0L-3UQgOw) znm5naV9T)gHEwQyxUBUKeM%21^YhCF)bxlSv<87wBbrn~U;Y=p5EJZ^4ldQ~oe@`) zmTzwhq!zP8-d3}GIzaHSYK!&`uu{5g5Rp?mmc#(0pIE4acXxK&mgLJ_WH=?ejG~>2 z+^x?C1C092cIxA`gTbf4$Ijuk*vd|pQ5xiB`$FwiueE$RpZOR481{I2@7L^=!>I!o zADWKgG$!A4Pm8{ABr)IooqzUw@s1z;hSs=DSQUkUO*L)#qUys0{hD%2v54tFYMD}8 zRRZqW`IF3|B7FbUV@Au?stWQB3^Gxr!-UF|F+l;UC3d>w!N|Y7Zvlu8wx;k4fd(sw}6CGC#!fHLXg822_Jr_ObmY()*Z8CAC9Z7BrW0Y}L7M-i(H z0WxdNBjc#}My1w_l@uyZPda1F3D}Q`b%R7PVX7?2Q4Fd z&yB5~tRm1+wg+*C?kd~xEc4#tL;vQr_&I$mAP0}3Lnn{1uj_&1I03uqL-&uf43T&+ zAkJoW)ipo7VdRvS!(7xDJTvbqAc!ICMZZ{9T&?V|vq<@0SPlfvxG)J@1tBx0gU-&Z zxbfe*nCI$JuV4PGK_3=sfKGP%-S%=a?$NED{RN*d`dTu_}zsKI>AjVI(6afcwR#fM=it2#ad7 z#2v%tmh)x?$GvM;k2+_?K6QX9&oWqM@6Tm|C%NUU7HC%HJf0V?h)171sVN|dDcBWK z=rIs44f1obJyp@DD*t+Nz|JQy%RD;90Hg>^q^%ju6u^URvM0|zmMmZQs(&88<&EF& z48yd_9K*NM@cFlH4&DNpuwiqj9cOT{`Nsr&+wbqs`u~L={?jdAfU)`t>f|ia93{l- zo-vBqKHt%Q+cqs&YpX=Nd`x)exP#U{DEptFgZF`Hn`fL}Rj9on+Osg@eb~(THwUU4w zZ43Ni6%?sHFe8G1mD)GoCfAUI7XSQY855)*tS96^-vrN)WIOnBIZYe&3+cS$R~GxV zfA9~!7MDD8s5=GQz~pOgeRJ?;$c3L{`#kQukFoJx0QLGUU;dwvZysoc@o;fMiKd&W zs<)^!95G3^ic4KvmQZ0G0Wvy?ta4#nUpCpDNYEz7HbZfn6{%WMuf05c)N{Z6g+=#v zPpS-+v*?vk6KWDW!Pjb~@v%~M_noz98!zr>jSqf_=B6D$&g}|MLY{i5&C@6}=Zl{S z&c(pw0laqR)vg}pdqP`WW^M_uI8qt@@}mVxB2b6)mcYVT$=xGYt>tWIy}j7nd6+%OCzz`MzIxBdoG9l>UemDgV=YY$c^bvqZ*7 zxhm{Sic9J;zC#w3LQMKfTF6nP8KqlBe@S{%bD{PvMTztl3PzN{rpm+R1!2zbKFLr0 z+?$;QoOnD$ncnc?{>8P+G0yTjZT(y{8LIW@eq3DSbyK;!^ST}To(8Pisc-(vg}r?yqPNHr zRu&)hDPWk!NUMep(7DWKwJlpW+WuENc$o{awG}1;4L60zU_)C2SgadgbNY z>n`)+fAd`SfA0t0e7d6yIhM4GBJwufi3juP6>3K+g6=(kcl@!kak{Q9cw`xd=?)JK zqU>VnH2qNXhRWlm{$2<(2WGBW1`3)|v`Gbx7d#yi9-9`w|?pW=J=}Mx}7^sN}&Rj0>N2VJV<(eo^s*fx*%#WJra^DB#Gt4gVKw1R+G2U8QY|Fk8RBIO?FaK5U1 zhRALk4OWb~Jyn4KBgxgezTco=CuU$BvkFx*iFJ_9nARC7vf-{)qj)Lkb_BQ-4KY3{ z_{$i87ael3KPAC3{OR$Ynz0|7lh`~&Xc~^kuS(&=vrFm=JnJSdYr<@>NFau1;EIY* zQlh0nyI2G6D2Xp-!FraM2iNXn{`OCNd-q4;{K|{pdC?{}=lu#!qgDKT`$eQUSYRFc z`@ZKNWZSO2`bh|#+)eVS1A#l=Z_PN?cMhgkz)G@4am!_EzAQ6O3me-tW|YzQlQxhY z6smwb2c%kOZw1KUd;A80E<1j3d=;$mlQS-R!U^c7#@2hBU;E14?+>}|dbH~cEiG{d z66-Uv*3GMOoOEZ(=F9%!j^D`W>KzNb8TPoDn2>g!C~6x=JW_DR(dl$egH%>7Jw(gB zWSV8PD?rF1$9SUAZOt`W5|9Xh_v`mBb@}-Zd_4Z)Km6Lk69rOf_B{Bz@f@~R=QpoA zQ;o{`3Ty!pF1MbxzW2uhKjZWNTzRq0M)igpthrdmAqB|C$a zMgx=cw(Q=X%gd!HXh;k0!gU0m*;eJCXrr!_F8cxCX!(Bt;flX&T+HGXFmdR zQD4rtGR5BV=kwLsxV^H!9EzK{8BFf zwFoF&ZF%w5l55W$)m}UbU&ryiI=75Ye50wmjXGWVt9hxUkrpEOYPNR!TJxf5JBBXF z#knuq2`S@~b*?df?iW6O8yfQ2gW>*|kQ;bx?Jm`(Wzd)MdTp6_4C2G8aS0xyUD!A= z>CJY7W@ufBfj?ds=8p>CO`mel;O=j?$Euj6O9zAS3%kxC83Zr@EWpy&x=sCpftORU zXM9Y0Ygw#uX&vu;=O3uA1~z{0U~DUDMcCdqL#=HL%J2$+J}>XObKU$iKL6YBD~>;J ztP=Rvr;h-HL3Y5~R}ekPFJRTjEI*RzmDE~ejKs}RIyz9hJz6YYfls9iI539a0yE4| znxA7|dMpWMA&Mb6ez1G$FI$#AvmCW54_?{W-TpIePcwl_XvfrN zwOJ8eF}(aqfi8yyx!i(hHJ}#B?E0ZHrJ|;+^?PQR@YqqIxJD_j2!@$UC;WrNkQG%QpV7)PMc=Vr_q9wVkL&RLwc^tkvu z*q!b@jCY9{^qQapo6N5iATEBK)(ho}t&Q64pD+4*GajbP#Up=y8wA

1dx9zQpAu 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 z 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 literal 0 HcmV?d00001 diff --git a/registerSW.js b/registerSW.js new file mode 100644 index 00000000..26fc40d0 --- /dev/null +++ b/registerSW.js @@ -0,0 +1 @@ +if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/zerdocs/sw.js', { scope: '/zerdocs/' })})} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..078504b1 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://fxzer.github.io/BackEnd/NodeJS/MongoDB%E7%AC%94%E8%AE%B0https://fxzer.github.io/BackEnd/NodeJS/Node%E5%A4%A7%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0https://fxzer.github.io/BackEnd/NodeJS/Node%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0https://fxzer.github.io/BackEnd/NodeJS/Node%E7%AE%80%E5%8D%95%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6https://fxzer.github.io/BackEnd/Server/Docker%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0https://fxzer.github.io/BackEnd/Server/Nginx%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0https://fxzer.github.io/Framework/Angular/Angular%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93%E4%B8%80https://fxzer.github.io/Framework/Angular/Angular%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93%E4%B8%89https://fxzer.github.io/Framework/Angular/Angular%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93%E4%BA%8Chttps://fxzer.github.io/Framework/React/React%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93%E4%B8%80https://fxzer.github.io/Framework/Vue/Vite%E5%8E%9F%E7%90%86%E5%AD%A6%E4%B9%A0https://fxzer.github.io/Framework/Vue/Vue3%E8%A1%A5%E6%BC%8F%E7%AC%94%E8%AE%B0https://fxzer.github.io/Framework/Vue/%E5%88%86%E9%A1%B5%E4%B8%8E%E6%90%9C%E7%B4%A2%E6%9D%A1%E4%BB%B6%E8%AE%B0%E5%BD%95%E5%B9%B6%E5%9B%9E%E6%98%BE%E4%BC%98%E5%8C%96https://fxzer.github.io/Framework/Vue/%E5%88%97%E8%A1%A8%E6%9C%80%E5%90%8E%E4%B8%80%E6%9D%A1%E6%95%B0%E6%8D%AE%E5%88%A0%E9%99%A4%E5%A4%84%E7%90%86https://fxzer.github.io/FrontEnd/CSS/Grid%E5%B8%83%E5%B1%80%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0https://fxzer.github.io/FrontEnd/CSS/%E5%B8%B8%E7%94%A8%E4%BB%A3%E7%A0%81%E6%AE%B5https://fxzer.github.io/FrontEnd/CSS/%E6%8F%AD%E7%A7%98%E8%AF%BB%E4%B9%A6%E6%91%98%E8%A6%81https://fxzer.github.io/FrontEnd/Git/Git%E5%B8%B8%E7%94%A8%E6%93%8D%E4%BD%9Chttps://fxzer.github.io/FrontEnd/Git/Terminal%E7%BB%88%E7%AB%AF%E7%BE%8E%E5%8C%96https://fxzer.github.io/FrontEnd/Git/%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AA%E5%B9%B3%E5%8F%B0SSHhttps://fxzer.github.io/FrontEnd/JavaScript/async%E4%B8%8Eawaithttps://fxzer.github.io/FrontEnd/JavaScript/%E4%BB%A3%E7%A0%81%E5%88%86%E6%94%AF%E4%BC%98%E5%8C%96https://fxzer.github.io/FrontEnd/JavaScript/%E5%9B%BE%E7%89%87%E6%87%92%E5%8A%A0%E8%BD%BDhttps://fxzer.github.io/FrontEnd/JavaScript/%E5%9F%BA%E7%A1%80%E5%A4%8D%E4%B9%A0%E4%B8%80https://fxzer.github.io/FrontEnd/JavaScript/%E5%9F%BA%E7%A1%80%E5%A4%8D%E4%B9%A0%E4%BA%8Chttps://fxzer.github.io/FrontEnd/JavaScript/%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95https://fxzer.github.io/FrontEnd/JavaScript/%E6%89%8B%E5%86%99Promisehttps://fxzer.github.io/FrontEnd/JavaScript/%E6%95%B0%E6%8D%AE%E5%8E%BB%E9%87%8Dhttps://fxzer.github.io/FrontEnd/JavaScript/%E6%95%B0%E7%BB%84%E6%B1%82%E9%9B%86%E5%90%88https://fxzer.github.io/FrontEnd/JavaScript/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9Fhttps://fxzer.github.io/FrontEnd/JavaScript/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8Fhttps://fxzer.github.io/FrontEnd/JavaScript/%E8%8E%B7%E5%8F%96%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84https://fxzer.github.io/FrontEnd/JavaScript/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0https://fxzer.github.io/FrontEnd/Shell/%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E8%84%9A%E6%9C%AChttps://fxzer.github.io/FrontEnd/TypeScript/%E5%88%9D%E5%AD%A6%E7%AC%94%E8%AE%B0https://fxzer.github.io/FrontEnd/TypeScript/%E8%BF%9B%E9%98%B6%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7https://fxzer.github.io/FrontEnd/TypeScript/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%AF%A6%E8%A7%A3https://fxzer.github.io/GoodTool/https://fxzer.github.io/Interview/Brower/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF%E6%9C%BA%E5%88%B6https://fxzer.github.io/Interview/Brower/%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BD%91%E9%A1%B5%E8%AF%B7%E6%B1%82%E8%BF%87%E7%A8%8Bhttps://fxzer.github.io/Interview/Brower/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9Chttps://fxzer.github.io/Interview/CSS/%E5%9F%BA%E7%A1%80%E9%9D%A2%E8%AF%95%E9%A2%98https://fxzer.github.io/Interview/CSS/%E8%BF%9B%E9%98%B6%E9%9D%A2%E8%AF%95%E9%A2%98https://fxzer.github.io/Interview/CSS/%E9%AB%98%E7%BA%A7%E9%9D%A2%E8%AF%95%E9%A2%98https://fxzer.github.io/Interview/JavaScript/Promise%E7%9B%B8%E5%85%B3https://fxzer.github.io/Interview/JavaScript/%E5%8E%9F%E5%9E%8B%E4%B8%8E%E5%8E%9F%E5%9E%8B%E9%93%BEhttps://fxzer.github.io/Interview/JavaScript/%E5%9F%BA%E7%A1%80%E9%9D%A2%E8%AF%95%E9%A2%98https://fxzer.github.io/Interview/JavaScript/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95https://fxzer.github.io/Interview/JavaScript/%E8%BF%9B%E9%98%B6%E9%9D%A2%E8%AF%95%E9%A2%98https://fxzer.github.io/Interview/JavaScript/%E9%AB%98%E7%BA%A7%E9%9D%A2%E8%AF%95%E9%A2%98https://fxzer.github.io/Interview/Vue/Vue%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8E%9F%E7%90%86https://fxzer.github.io/Interview/Vue/Vue%E5%9F%BA%E7%A1%80%E7%AF%87https://fxzer.github.io/Interview/Vue/Vue%E5%A3%B0%E6%98%8E%E5%91%A8%E6%9C%9Fhttps://fxzer.github.io/Interview/Vue/Vue%E8%BF%9B%E9%98%B6%E7%AF%87https://fxzer.github.io/Interview/Vue/npm%20run%20xxx%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8Bhttps://fxzer.github.io/Interview/Vue/%E5%89%8D%E7%AB%AF%E9%A1%B9%E7%9B%AE%E4%BC%98%E5%8C%96https://fxzer.github.io/Interview/Vue/%E5%B8%B8%E8%A7%81Path%E5%8C%BA%E5%88%ABhttps://fxzer.github.io/Interview/Vue/%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4https://fxzer.github.io/Interview/https://fxzer.github.io/Problem/Graphical/Antv%E4%BB%A3%E7%A0%81%E7%89%87%E6%AE%B5%E9%9B%86%E9%94%A6https://fxzer.github.io/Problem/Graphical/Antv%E4%BD%BF%E7%94%A8%E6%80%BB%E7%BB%93https://fxzer.github.io/Problem/Graphical/Echarts%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93https://fxzer.github.io/Problem/Nuxt3/Nuxt3%E9%A1%B9%E7%9B%AE%E8%B8%A9%E5%9D%91https://fxzer.github.io/Problem/VitePress/VitePress%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95https://fxzer.github.io/Problem/VitePress/VuePress%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95https://fxzer.github.io/Problem/VueProject/Vue%E9%A1%B9%E7%9B%AE%E8%B8%A9%E5%9D%91%E4%B8%80https://fxzer.github.io/Problem/https://fxzer.github.io/zerdocshttps://fxzer.github.io/extra-pagemonthly0.8 \ No newline at end of file diff --git a/socialIcons.ts b/socialIcons.ts new file mode 100644 index 00000000..a5950059 --- /dev/null +++ b/socialIcons.ts @@ -0,0 +1,9 @@ + +export const icons = { + bilibili: `` +} \ No newline at end of file diff --git a/sw.js b/sw.js new file mode 100644 index 00000000..90362587 --- /dev/null +++ b/sw.js @@ -0,0 +1 @@ +if(!self.define){let e,s={};const r=(r,n)=>(r=new URL(r+".js",n).href,s[r]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=r,e.onload=s,document.head.appendChild(e)}else e=r,importScripts(r),s()})).then((()=>{let e=s[r];if(!e)throw new Error(`Module ${r} didn’t register its module`);return e})));self.define=(n,l)=>{const a=e||("document"in self?document.currentScript.src:"")||location.href;if(s[a])return;let i={};const d=e=>r(e,a),t={module:{uri:a},exports:i,require:d};s[a]=Promise.all(n.map((e=>t[e]||d(e)))).then((e=>(l(...e),i)))}}define(["./workbox-fa446783"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"404.html",revision:"e87db43fe77f4203f35b5630ea3a98f3"},{url:"assets/app.c5d8d5ce.js",revision:null},{url:"assets/BackEnd_NodeJS_MongoDB笔记.md.eb6021c2.js",revision:null},{url:"assets/BackEnd_NodeJS_MongoDB笔记.md.eb6021c2.lean.js",revision:null},{url:"assets/BackEnd_NodeJS_Node大文件上传.md.84c9f765.js",revision:null},{url:"assets/BackEnd_NodeJS_Node大文件上传.md.84c9f765.lean.js",revision:null},{url:"assets/BackEnd_NodeJS_Node学习笔记.md.f1b234ff.js",revision:null},{url:"assets/BackEnd_NodeJS_Node学习笔记.md.f1b234ff.lean.js",revision:null},{url:"assets/BackEnd_NodeJS_Node简单上传文件.md.faa27b4e.js",revision:null},{url:"assets/BackEnd_NodeJS_Node简单上传文件.md.faa27b4e.lean.js",revision:null},{url:"assets/BackEnd_Server_Docker学习笔记.md.d29feca6.js",revision:null},{url:"assets/BackEnd_Server_Docker学习笔记.md.d29feca6.lean.js",revision:null},{url:"assets/BackEnd_Server_Nginx学习笔记.md.9d658cc4.js",revision:null},{url:"assets/BackEnd_Server_Nginx学习笔记.md.9d658cc4.lean.js",revision:null},{url:"assets/chunks/@localSearchIndexroot.20abec5d.js",revision:null},{url:"assets/chunks/DemoWrap.1b6e7adf.js",revision:null},{url:"assets/chunks/framework.c53372a0.js",revision:null},{url:"assets/chunks/theme.1e9d2528.js",revision:null},{url:"assets/chunks/VPLocalSearchBox.0bede1e4.js",revision:null},{url:"assets/Framework_Angular_Angular基础总结一.md.25af9886.js",revision:null},{url:"assets/Framework_Angular_Angular基础总结一.md.25af9886.lean.js",revision:null},{url:"assets/Framework_Angular_Angular基础总结三.md.574a1956.js",revision:null},{url:"assets/Framework_Angular_Angular基础总结三.md.574a1956.lean.js",revision:null},{url:"assets/Framework_Angular_Angular基础总结二.md.0a8462a7.js",revision:null},{url:"assets/Framework_Angular_Angular基础总结二.md.0a8462a7.lean.js",revision:null},{url:"assets/Framework_React_React基础总结一.md.fc5d41af.js",revision:null},{url:"assets/Framework_React_React基础总结一.md.fc5d41af.lean.js",revision:null},{url:"assets/Framework_Vue_Vite原理学习.md.8895a11d.js",revision:null},{url:"assets/Framework_Vue_Vite原理学习.md.8895a11d.lean.js",revision:null},{url:"assets/Framework_Vue_Vue3补漏笔记.md.6422a5f9.js",revision:null},{url:"assets/Framework_Vue_Vue3补漏笔记.md.6422a5f9.lean.js",revision:null},{url:"assets/Framework_Vue_分页与搜索条件记录并回显优化.md.8805bdc2.js",revision:null},{url:"assets/Framework_Vue_分页与搜索条件记录并回显优化.md.8805bdc2.lean.js",revision:null},{url:"assets/Framework_Vue_列表最后一条数据删除处理.md.9f59b85b.js",revision:null},{url:"assets/Framework_Vue_列表最后一条数据删除处理.md.9f59b85b.lean.js",revision:null},{url:"assets/FrontEnd_CSS_Grid布局学习笔记.md.6624dd93.js",revision:null},{url:"assets/FrontEnd_CSS_Grid布局学习笔记.md.6624dd93.lean.js",revision:null},{url:"assets/FrontEnd_CSS_常用代码段.md.083fb786.js",revision:null},{url:"assets/FrontEnd_CSS_常用代码段.md.083fb786.lean.js",revision:null},{url:"assets/FrontEnd_CSS_揭秘读书摘要.md.3689a434.js",revision:null},{url:"assets/FrontEnd_CSS_揭秘读书摘要.md.3689a434.lean.js",revision:null},{url:"assets/FrontEnd_Git_Git常用操作.md.a0e87468.js",revision:null},{url:"assets/FrontEnd_Git_Git常用操作.md.a0e87468.lean.js",revision:null},{url:"assets/FrontEnd_Git_Terminal终端美化.md.6674896b.js",revision:null},{url:"assets/FrontEnd_Git_Terminal终端美化.md.6674896b.lean.js",revision:null},{url:"assets/FrontEnd_Git_配置多个平台SSH.md.49289c60.js",revision:null},{url:"assets/FrontEnd_Git_配置多个平台SSH.md.49289c60.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_async与await.md.d21c9cb0.js",revision:null},{url:"assets/FrontEnd_JavaScript_async与await.md.d21c9cb0.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_代码分支优化.md.e8fda00c.js",revision:null},{url:"assets/FrontEnd_JavaScript_代码分支优化.md.e8fda00c.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_图片懒加载.md.3d5465d0.js",revision:null},{url:"assets/FrontEnd_JavaScript_图片懒加载.md.3d5465d0.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_基础复习一.md.a8906ce7.js",revision:null},{url:"assets/FrontEnd_JavaScript_基础复习一.md.a8906ce7.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_基础复习二.md.8f89af07.js",revision:null},{url:"assets/FrontEnd_JavaScript_基础复习二.md.8f89af07.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_常见算法.md.0cd56de3.js",revision:null},{url:"assets/FrontEnd_JavaScript_常见算法.md.0cd56de3.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_手写Promise.md.fbddbbf5.js",revision:null},{url:"assets/FrontEnd_JavaScript_手写Promise.md.fbddbbf5.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_数据去重.md.f1eaba48.js",revision:null},{url:"assets/FrontEnd_JavaScript_数据去重.md.f1eaba48.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_数组求集合.md.9e71e873.js",revision:null},{url:"assets/FrontEnd_JavaScript_数组求集合.md.9e71e873.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_文件系统.md.1488f287.js",revision:null},{url:"assets/FrontEnd_JavaScript_文件系统.md.1488f287.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_正则表达式.md.a9560fb8.js",revision:null},{url:"assets/FrontEnd_JavaScript_正则表达式.md.a9560fb8.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_获取目录结构.md.f15b6a8f.js",revision:null},{url:"assets/FrontEnd_JavaScript_获取目录结构.md.f15b6a8f.lean.js",revision:null},{url:"assets/FrontEnd_JavaScript_高阶函数.md.f3e81d0b.js",revision:null},{url:"assets/FrontEnd_JavaScript_高阶函数.md.f3e81d0b.lean.js",revision:null},{url:"assets/FrontEnd_Shell_自动部署脚本.md.7ce896dd.js",revision:null},{url:"assets/FrontEnd_Shell_自动部署脚本.md.7ce896dd.lean.js",revision:null},{url:"assets/FrontEnd_TypeScript_初学笔记.md.a7be054a.js",revision:null},{url:"assets/FrontEnd_TypeScript_初学笔记.md.a7be054a.lean.js",revision:null},{url:"assets/FrontEnd_TypeScript_进阶使用技巧.md.21fda5ca.js",revision:null},{url:"assets/FrontEnd_TypeScript_进阶使用技巧.md.21fda5ca.lean.js",revision:null},{url:"assets/FrontEnd_TypeScript_配置文件详解.md.7a55465d.js",revision:null},{url:"assets/FrontEnd_TypeScript_配置文件详解.md.7a55465d.lean.js",revision:null},{url:"assets/GoodTool_index.md.2cde5d0e.js",revision:null},{url:"assets/GoodTool_index.md.2cde5d0e.lean.js",revision:null},{url:"assets/index.md.4cc1630f.js",revision:null},{url:"assets/index.md.4cc1630f.lean.js",revision:null},{url:"assets/Interview_Brower_事件循环机制.md.9f053692.js",revision:null},{url:"assets/Interview_Brower_事件循环机制.md.9f053692.lean.js",revision:null},{url:"assets/Interview_Brower_浏览器网页请求过程.md.1acb73dd.js",revision:null},{url:"assets/Interview_Brower_浏览器网页请求过程.md.1acb73dd.lean.js",revision:null},{url:"assets/Interview_Brower_计算机网络.md.73c84072.js",revision:null},{url:"assets/Interview_Brower_计算机网络.md.73c84072.lean.js",revision:null},{url:"assets/Interview_CSS_基础面试题.md.b72bdb12.js",revision:null},{url:"assets/Interview_CSS_基础面试题.md.b72bdb12.lean.js",revision:null},{url:"assets/Interview_CSS_进阶面试题.md.6b9b42f1.js",revision:null},{url:"assets/Interview_CSS_进阶面试题.md.6b9b42f1.lean.js",revision:null},{url:"assets/Interview_CSS_高级面试题.md.63a54546.js",revision:null},{url:"assets/Interview_CSS_高级面试题.md.63a54546.lean.js",revision:null},{url:"assets/Interview_index.md.ff0a75dc.js",revision:null},{url:"assets/Interview_index.md.ff0a75dc.lean.js",revision:null},{url:"assets/Interview_JavaScript_Promise相关.md.1015a7af.js",revision:null},{url:"assets/Interview_JavaScript_Promise相关.md.1015a7af.lean.js",revision:null},{url:"assets/Interview_JavaScript_原型与原型链.md.4ad216b5.js",revision:null},{url:"assets/Interview_JavaScript_原型与原型链.md.4ad216b5.lean.js",revision:null},{url:"assets/Interview_JavaScript_基础面试题.md.0df982a7.js",revision:null},{url:"assets/Interview_JavaScript_基础面试题.md.0df982a7.lean.js",revision:null},{url:"assets/Interview_JavaScript_字符串常用方法.md.4808f793.js",revision:null},{url:"assets/Interview_JavaScript_字符串常用方法.md.4808f793.lean.js",revision:null},{url:"assets/Interview_JavaScript_进阶面试题.md.c89e986d.js",revision:null},{url:"assets/Interview_JavaScript_进阶面试题.md.c89e986d.lean.js",revision:null},{url:"assets/Interview_JavaScript_高级面试题.md.0abc2056.js",revision:null},{url:"assets/Interview_JavaScript_高级面试题.md.0abc2056.lean.js",revision:null},{url:"assets/Interview_Vue_npm run xxx执行过程.md.9da37746.js",revision:null},{url:"assets/Interview_Vue_npm run xxx执行过程.md.9da37746.lean.js",revision:null},{url:"assets/Interview_Vue_Vue响应式原理.md.2eeac150.js",revision:null},{url:"assets/Interview_Vue_Vue响应式原理.md.2eeac150.lean.js",revision:null},{url:"assets/Interview_Vue_Vue基础篇.md.d7fd744f.js",revision:null},{url:"assets/Interview_Vue_Vue基础篇.md.d7fd744f.lean.js",revision:null},{url:"assets/Interview_Vue_Vue声明周期.md.4220f397.js",revision:null},{url:"assets/Interview_Vue_Vue声明周期.md.4220f397.lean.js",revision:null},{url:"assets/Interview_Vue_Vue进阶篇.md.786b9622.js",revision:null},{url:"assets/Interview_Vue_Vue进阶篇.md.786b9622.lean.js",revision:null},{url:"assets/Interview_Vue_前端项目优化.md.3cd67a0e.js",revision:null},{url:"assets/Interview_Vue_前端项目优化.md.3cd67a0e.lean.js",revision:null},{url:"assets/Interview_Vue_常见Path区别.md.56f4fc59.js",revision:null},{url:"assets/Interview_Vue_常见Path区别.md.56f4fc59.lean.js",revision:null},{url:"assets/Interview_Vue_自定义指令.md.3d2ea0a9.js",revision:null},{url:"assets/Interview_Vue_自定义指令.md.3d2ea0a9.lean.js",revision:null},{url:"assets/Problem_Graphical_Antv代码片段集锦.md.3d28f150.js",revision:null},{url:"assets/Problem_Graphical_Antv代码片段集锦.md.3d28f150.lean.js",revision:null},{url:"assets/Problem_Graphical_Antv使用总结.md.10b596c9.js",revision:null},{url:"assets/Problem_Graphical_Antv使用总结.md.10b596c9.lean.js",revision:null},{url:"assets/Problem_Graphical_Echarts问题总结.md.fe67d408.js",revision:null},{url:"assets/Problem_Graphical_Echarts问题总结.md.fe67d408.lean.js",revision:null},{url:"assets/Problem_index.md.724652c6.js",revision:null},{url:"assets/Problem_index.md.724652c6.lean.js",revision:null},{url:"assets/Problem_Nuxt3_Nuxt3项目踩坑.md.e3bdda07.js",revision:null},{url:"assets/Problem_Nuxt3_Nuxt3项目踩坑.md.e3bdda07.lean.js",revision:null},{url:"assets/Problem_VitePress_VitePress踩坑记录.md.007e02bc.js",revision:null},{url:"assets/Problem_VitePress_VitePress踩坑记录.md.007e02bc.lean.js",revision:null},{url:"assets/Problem_VitePress_VuePress踩坑记录.md.d7553dcf.js",revision:null},{url:"assets/Problem_VitePress_VuePress踩坑记录.md.d7553dcf.lean.js",revision:null},{url:"assets/Problem_VueProject_Vue项目踩坑一.md.5d32b46a.js",revision:null},{url:"assets/Problem_VueProject_Vue项目踩坑一.md.5d32b46a.lean.js",revision:null},{url:"assets/style.ca30dd5f.css",revision:null},{url:"BackEnd/NodeJS/MongoDB笔记.html",revision:"6fa1aed7030f69f08f405acf2502d0d3"},{url:"BackEnd/NodeJS/Node大文件上传.html",revision:"a557bb2dd4ad1edd3a67f4e634f9912d"},{url:"BackEnd/NodeJS/Node学习笔记.html",revision:"57b5a3d214f0c349e56192cfd8562f18"},{url:"BackEnd/NodeJS/Node简单上传文件.html",revision:"65613222629d7db41f242f0ad4bd711a"},{url:"BackEnd/Server/Docker学习笔记.html",revision:"036b2e33423baa47b63cec7e83aca161"},{url:"BackEnd/Server/Nginx学习笔记.html",revision:"12600bea4455d96bc3a30df9255ef85e"},{url:"Framework/Angular/Angular基础总结一.html",revision:"e67a1a600c4c4f3dad7e3bf3a9e9cfad"},{url:"Framework/Angular/Angular基础总结三.html",revision:"c6575496a2dc99033945fb6ec1ac5e25"},{url:"Framework/Angular/Angular基础总结二.html",revision:"2c57128e00edd6f16e6bf09883deca35"},{url:"Framework/React/React基础总结一.html",revision:"7b02257863eb625a82af0a0a7b5a876b"},{url:"Framework/Vue/Vite原理学习.html",revision:"d2eb221ec2f13fc992e8e665d5e4bf10"},{url:"Framework/Vue/Vue3补漏笔记.html",revision:"653ca29c4ed57a8840b7b9f8b4fdefb7"},{url:"Framework/Vue/分页与搜索条件记录并回显优化.html",revision:"d1d6dde8647f9562ca7c97405619079c"},{url:"Framework/Vue/列表最后一条数据删除处理.html",revision:"aa839c8a35315c0d130fc13183924e23"},{url:"FrontEnd/CSS/Grid布局学习笔记.html",revision:"312e04585f9184445a70710100d1f3d4"},{url:"FrontEnd/CSS/常用代码段.html",revision:"102f3df98828d0145c7f34b40d1078b1"},{url:"FrontEnd/CSS/揭秘读书摘要.html",revision:"a1324274b090e440e2d8ced238964b27"},{url:"FrontEnd/Git/Git常用操作.html",revision:"9727faad3302669341d79057ebd76ce8"},{url:"FrontEnd/Git/Terminal终端美化.html",revision:"77ed1ffaeaef91c0319d04196ecf5645"},{url:"FrontEnd/Git/配置多个平台SSH.html",revision:"53d170a276eb2e573d7cae1046e74a03"},{url:"FrontEnd/JavaScript/async与await.html",revision:"db67d6ac449ae54dc97f3e745acf7637"},{url:"FrontEnd/JavaScript/代码分支优化.html",revision:"af9a0de863a26196a08cf0812660b01b"},{url:"FrontEnd/JavaScript/图片懒加载.html",revision:"3f2142a3b6fe5d945e4e70b2b4b33253"},{url:"FrontEnd/JavaScript/基础复习一.html",revision:"a86153546f40713fd4b13f3908bf26ae"},{url:"FrontEnd/JavaScript/基础复习二.html",revision:"9b9de47e72d16f98664638e0e17bffba"},{url:"FrontEnd/JavaScript/常见算法.html",revision:"f2d3662bae834b195646b962e41d3cac"},{url:"FrontEnd/JavaScript/手写Promise.html",revision:"83bb23fbf5892a1fb6fc2e4c25b5bee6"},{url:"FrontEnd/JavaScript/数据去重.html",revision:"64c558c1d094bc3113b8acaf93ae9271"},{url:"FrontEnd/JavaScript/数组求集合.html",revision:"91d0f79c6fd67be0187c968a4874e062"},{url:"FrontEnd/JavaScript/文件系统.html",revision:"9e0d578342c81b1086c0f149ee6c8814"},{url:"FrontEnd/JavaScript/正则表达式.html",revision:"96c33365b3264af79318e05c750412a5"},{url:"FrontEnd/JavaScript/获取目录结构.html",revision:"9035f9cd169b5e3dcf5027fe9197cf79"},{url:"FrontEnd/JavaScript/高阶函数.html",revision:"21809b2db7cad48d62235f1c0227814b"},{url:"FrontEnd/Shell/自动部署脚本.html",revision:"9e3170e934f8f93b114b9d3d29dadd83"},{url:"FrontEnd/TypeScript/初学笔记.html",revision:"b9ba3d395a50cdcfbd5f0779ff8a8f57"},{url:"FrontEnd/TypeScript/进阶使用技巧.html",revision:"5a591457e1a22d5f30f9f2ed98ce3cd6"},{url:"FrontEnd/TypeScript/配置文件详解.html",revision:"d4a87bd4aacd9c2f27a415ad66e880ff"},{url:"GoodTool/index.html",revision:"3acfad58f9cee976a30e2f0fa31b067d"},{url:"index.html",revision:"b1aaa1588b5288ad57cc0f1ae588b40c"},{url:"Interview/Brower/事件循环机制.html",revision:"ed47d89475d03693886b95bc26bec037"},{url:"Interview/Brower/浏览器网页请求过程.html",revision:"37c2bcbec782d54bab93edfd54a74d9e"},{url:"Interview/Brower/计算机网络.html",revision:"e61d17ab4d98fd4acd8119b518b33f76"},{url:"Interview/CSS/基础面试题.html",revision:"79b7323c8c6af203bc52965aeb2edd42"},{url:"Interview/CSS/进阶面试题.html",revision:"b4a184072e964a310db7d4a28d2c6e92"},{url:"Interview/CSS/高级面试题.html",revision:"6d6c2404f111046fb5e443f173bdd3d8"},{url:"Interview/index.html",revision:"d6374db1df3a19ab6c3e73271739c4a8"},{url:"Interview/JavaScript/Promise相关.html",revision:"d571639d139453ac82949d856c089446"},{url:"Interview/JavaScript/原型与原型链.html",revision:"80a93283f8c3553aea2018366dfc7938"},{url:"Interview/JavaScript/基础面试题.html",revision:"7f417e6acc4e66ac3939b02fcdda4243"},{url:"Interview/JavaScript/字符串常用方法.html",revision:"f6886427cae7510cffa2fb26528dd49c"},{url:"Interview/JavaScript/进阶面试题.html",revision:"3027f402aa7f5775169a9d8be2fde950"},{url:"Interview/JavaScript/高级面试题.html",revision:"eec2d696b50de3f8d1b94018ec1ec135"},{url:"Interview/Vue/npm run xxx执行过程.html",revision:"78a8f0379f08540ea148ed63a8ff11e7"},{url:"Interview/Vue/Vue响应式原理.html",revision:"d89f8d2484ede5cd1fbc210e42dc2249"},{url:"Interview/Vue/Vue基础篇.html",revision:"0f4f72a16a37e5920456904a9defe044"},{url:"Interview/Vue/Vue声明周期.html",revision:"3dfe74095a54aa6febb5a2c3fe8ed5ac"},{url:"Interview/Vue/Vue进阶篇.html",revision:"8ba96c5710ab321e363c43c34240e534"},{url:"Interview/Vue/前端项目优化.html",revision:"6c9f8b1f918049515a6415c1eba88b5c"},{url:"Interview/Vue/常见Path区别.html",revision:"1d3968c627cbd11c97195f81b459fc2b"},{url:"Interview/Vue/自定义指令.html",revision:"36d433972846dacccba61de5673b88a3"},{url:"Problem/Graphical/Antv代码片段集锦.html",revision:"0250c0eded3d726adaf675f98a3aa1c6"},{url:"Problem/Graphical/Antv使用总结.html",revision:"c96fcfd5207a2f9ae6eaa25ceae12547"},{url:"Problem/Graphical/Echarts问题总结.html",revision:"50bf018028b723263c35e01b39f06a73"},{url:"Problem/index.html",revision:"3b6bbc63eedfa0dbbe51b7a2f16da77e"},{url:"Problem/Nuxt3/Nuxt3项目踩坑.html",revision:"5f2a128296e7b96bfa5c207b00156b8d"},{url:"Problem/VitePress/VitePress踩坑记录.html",revision:"e6c8b8704bee434c147e1c01d6b69a10"},{url:"Problem/VitePress/VuePress踩坑记录.html",revision:"59afc482bb57cbdb3ef81b094db0cd9e"},{url:"Problem/VueProject/Vue项目踩坑一.html",revision:"4556e5986a340c0896eac348eeb8dfa1"},{url:"registerSW.js",revision:"385b79d064fe7f8195f90acea5c7388b"},{url:"pwa-512x512.png",revision:"cb765af63e04e54c9125f175a7b67333"},{url:"pwa-192x192.png",revision:"26a17df838f4a40e035971d0f34b32c1"},{url:"manifest.webmanifest",revision:"b9bd1c040f779c7165c5d3fff7644134"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))})); diff --git a/workbox-fa446783.js b/workbox-fa446783.js new file mode 100644 index 00000000..8c012bc7 --- /dev/null +++ b/workbox-fa446783.js @@ -0,0 +1 @@ +define(["exports"],(function(t){"use strict";try{self["workbox:core:7.0.0"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:7.0.0"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class r extends i{constructor(t,e,s){super((({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)}),e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",(t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})})));t.waitUntil(s),t.ports&&t.ports[0]&&s.then((()=>t.ports[0].postMessage(!0)))}}))}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:i,route:r}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=r&&r.handler;const c=t.method;if(!o&&this.i.has(c)&&(o=this.i.get(c)),!o)return;let a;try{a=o.handle({url:s,request:t,event:e,params:i})}catch(t){a=Promise.reject(t)}const h=r&&r.catchHandler;return a instanceof Promise&&(this.o||h)&&(a=a.catch((async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:i})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n}))),a}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this.t.get(s.method)||[];for(const r of i){let i;const o=r.match({url:t,sameOrigin:e,request:s,event:n});if(o)return i=o,(Array.isArray(i)&&0===i.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(i=void 0),{route:r,params:i}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let c;const a=()=>(c||(c=new o,c.addFetchListener(),c.addCacheListener()),c);function h(t,e,n){let o;if("string"==typeof t){const s=new URL(t,location.href);o=new i((({url:t})=>t.href===s.href),e,n)}else if(t instanceof RegExp)o=new r(t,e,n);else if("function"==typeof t)o=new i(t,e,n);else{if(!(t instanceof i))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});o=t}return a().registerRoute(o),o}const u={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},l=t=>[u.prefix,t,u.suffix].filter((t=>t&&t.length>0)).join("-"),f=t=>t||l(u.precache),w=t=>t||l(u.runtime);function d(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:7.0.0"]&&_()}catch(t){}function p(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),r=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:r.href}}class y{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class g{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.h.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.h=t}}let R;async function m(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const i=t.clone(),r={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=e?e(r):r,c=function(){if(void 0===R){const t=new Response("");if("body"in t)try{new Response(t.body),R=!0}catch(t){R=!1}R=!1}return R}()?i.body:await i.blob();return new Response(c,o)}function v(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class q{constructor(){this.promise=new Promise(((t,e)=>{this.resolve=t,this.reject=e}))}}const U=new Set;try{self["workbox:strategies:7.0.0"]&&_()}catch(t){}function L(t){return"string"==typeof t?new Request(t):t}class b{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,this.l=t,this.p=new q,this.R=[],this.m=[...t.plugins],this.v=new Map;for(const t of this.m)this.v.set(t,{});this.event.waitUntil(this.p.promise)}async fetch(t){const{event:e}=this;let n=L(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const i=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const r=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.l.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:r,response:t});return t}catch(t){throw i&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:i.clone(),request:r.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=L(t);let s;const{cacheName:n,matchOptions:i}=this.l,r=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},i),{cacheName:n});s=await caches.match(r,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:i,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(t,e){const n=L(t);var i;await(i=0,new Promise((t=>setTimeout(t,i))));const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=r.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const c=await this.q(e);if(!c)return!1;const{cacheName:a,matchOptions:h}=this.l,u=await self.caches.open(a),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const i=v(e.url,s);if(e.url===i)return t.match(e,n);const r=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,r);for(const e of o)if(i===v(e.url,s))return t.match(e,n)}(u,r.clone(),["__WB_REVISION__"],h):null;try{await u.put(r,l?c.clone():c)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of U)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:a,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.u[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=L(await t({mode:e,request:n,event:this.event,params:this.params}));this.u[s]=n}return this.u[s]}hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.l.plugins)if("function"==typeof e[t]){const s=this.v.get(e),n=n=>{const i=Object.assign(Object.assign({},n),{state:s});return e[t](i)};yield n}}waitUntil(t){return this.R.push(t),t}async doneWaiting(){let t;for(;t=this.R.shift();)await t}destroy(){this.p.resolve(null)}async q(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class C{constructor(t={}){this.cacheName=w(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,i=new b(this,{event:e,request:s,params:n}),r=this.U(i,s,e);return[r,this.L(r,i,s,e)]}async U(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(i=await this._(e,t),!i||"error"===i.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const r of t.iterateCallbacks("handlerDidError"))if(i=await r({error:s,event:n,request:e}),i)break;if(!i)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))i=await s({event:n,request:e,response:i});return i}async L(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:i}),await e.doneWaiting()}catch(t){t instanceof Error&&(r=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:i,error:r}),e.destroy(),r)throw r}}class E extends C{constructor(t={}){t.cacheName=f(t.cacheName),super(t),this.C=!1!==t.fallbackToNetwork,this.plugins.push(E.copyRedirectedCacheableResponsesPlugin)}async _(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.O(t,e):await this.N(t,e))}async N(t,e){let n;const i=e.params||{};if(!this.C)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=i.integrity,r=t.integrity,o=!r||r===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?r||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.k(),await e.cachePut(t,n.clone()))}return n}async O(t,e){this.k();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}k(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==E.copyRedirectedCacheableResponsesPlugin&&(n===E.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(E.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}E.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},E.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await m(t):t};class O{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.K=new Map,this.P=new Map,this.T=new Map,this.l=new E({cacheName:f(t),plugins:[...e,new g({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.l}precache(t){this.addToCacheList(t),this.W||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.W=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=p(n),r="string"!=typeof n&&n.revision?"reload":"default";if(this.K.has(i)&&this.K.get(i)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.K.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.T.has(t)&&this.T.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:i});this.T.set(t,n.integrity)}if(this.K.set(i,t),this.P.set(i,r),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return d(t,(async()=>{const e=new y;this.strategy.plugins.push(e);for(const[e,s]of this.K){const n=this.T.get(s),i=this.P.get(e),r=new Request(e,{integrity:n,cache:i,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}}))}activate(t){return d(t,(async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.K.values()),n=[];for(const i of e)s.has(i.url)||(await t.delete(i),n.push(i.url));return{deletedURLs:n}}))}getURLsToCacheKeys(){return this.K}getCachedURLs(){return[...this.K.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.K.get(e.href)}getIntegrityForCacheKey(t){return this.T.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}let x;const N=()=>(x||(x=new O),x);class k extends i{constructor(t,e){super((({request:s})=>{const n=t.getURLsToCacheKeys();for(const i of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:i}={}){const r=new URL(t,location.href);r.hash="",yield r.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some((t=>t.test(s)))&&t.searchParams.delete(s);return t}(r,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(i){const t=i({url:r});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(i);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}}),t.strategy)}}t.NavigationRoute=class extends i{constructor(t,{allowlist:e=[/./],denylist:s=[]}={}){super((t=>this.j(t)),t),this.M=e,this.S=s}j({url:t,request:e}){if(e&&"navigate"!==e.mode)return!1;const s=t.pathname+t.search;for(const t of this.S)if(t.test(s))return!1;return!!this.M.some((t=>t.test(s)))}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",(t=>{const e=f();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter((s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t));return await Promise.all(s.map((t=>self.caches.delete(t)))),s})(e).then((t=>{})))}))},t.clientsClaim=function(){self.addEventListener("activate",(()=>self.clients.claim()))},t.createHandlerBoundToURL=function(t){return N().createHandlerBoundToURL(t)},t.precacheAndRoute=function(t,e){!function(t){N().precache(t)}(t),function(t){const e=N();h(new k(e,t))}(e)},t.registerRoute=h}));

ZW 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�zBE;A6`RoYnYVbGchb9$^iIU2 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 literal 0 HcmV?d00001 diff --git a/assets/inter-roman-vietnamese.14ce25a6.woff2 b/assets/inter-roman-vietnamese.14ce25a6.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..5a9f9cb9ca0cd78b6ea2f3e5c9d2838dc8895598 GIT binary patch literal 8492 zcmV+{A=BP>Pew8T0RR9103j>@5dZ)H07h5<03gEv0|eaw00000000000000000000 z0000Qfg~G@2plRuNLE2of^Y_4KT}jeRDl`*f;ca13aJRB4KTl60X7081B4(8f)W4( zAO(aP2Ot}wL8BwA#{rDwTbk^j37MN0nnkm<&CYCgamAG{BQEv-@{h({JoW2WsiKJ{ zny6DpNHPoG)7pQYy0^RMEdaY!8%0bCP)`3Bl0b67#zmoxM+wMNKk&@$|J=(RT-bHH z&ZRfSMH4riXiQO2mtGhuDmm0S*_?%n8{4L$t(=MqgOqF)PiZY%M!9Mg`Sy%wXsdWi zi&vE7_{K|0QofPlA|)dwE)T@Ldw-UVjnSme!@vrsm!}gjPXlfXhXJSKzO~;D_{{Ft zj#v{*BuL~hh*>+q?$fMk0}-VxizyHmlss&T2(Vn%$U|B3849(nV*F&`?B==1_Ccqdm|ZONTW&&@StM@DVh$ga-iLzu~Y&GUY_3sURj%X_ncfPmoA3C17NwajDXbzt)aEFj@Hu#+DKbyD?gcrUjTvlky0JwkaT2p z8AY2Qu-I6`8`6=EbfhC4=}1R9)LA0?t`iZ766832kO=LeFLgp3u?_&16bTh}*?wY` z29u=(+z0CbsIRUF)!9(t07}m;w`r94SH>0B--x_ovEiXmZ)gc(sTKfsm$@cOl_kKB zN)2Gol=8c&Goqr1n?d6e5Jt%HJd<)iXHgQ)^Rhmn93`fF;Kl{9m&So$tpP#T0KFe7K@E#vfJ8{t0S5CS zV4r0~E^7FF25T$%Y^d(U#(j8H@?`KvynmwSL7-2301rqk_+P&ibaEe_Wl#Eizfb8? zhcppoL>neROy zplht+UGz3~5sWb+6fE|u>f6a8;ijibrcN!R z%OtvX+N^2PENMf_Qh3-^ZZBP0X~#^do&u@bUbbu<9d(f8Z;AjxmY~QZqKntoYS(Di zuT}zdatJqJdZomZdPuNFvMCpctqloDU1yo2=sWVGFV@xOZs z8Je~B$nL}1Z$Ztb6hwWg5$8fQapIDgi53Qph^mk*Hojm4My|x$^mrcA%T`Sw%dY^} znZTQ{7W1K8YB{;I0Fw~8eEfiYFyufL?gUqb%oUWvLO~8<`P~D}eM2AkS6`i^g#Dt( zs7erIq=p4jf=yCgC)NEzzVhZKFM99dw$7%-d+enbyZcUaUTOK=Qz`MmVcC*x((=No zf=eB6X&VM<(ju}X3Cu>1$rdt2H7O0#$CpeKG|Q8X6ar`_F6r@xQM)B!XfbODc&O_Q zYuK=*qg3fxHX8EAGMe{pF<4BgBpdBUCLh^A!qyp`s>or4AgGzw9IG?7!)~nCUHi02 zR=O_GM(k#zdYSbSujOV(`(?9{=^5o5Nh@6-on%Z#U0)fldj0x&5kM!L@R5=B~ zvSP~{r#D|*3UxTEyXk4ArojO;^ z83*hm!k#W19N#u`S!$4EzN@o}Usi<>v{*o09>D?P1H{Uf4v~WDJ}OFq@w;d=_t=G# zE%!2SG|7D_ELvRgPWq?7BKmsp!@JY%061j8VVu9pYxG_w!Z$mfzG$EKp_Abu98A?< z-y@*>`n#7Ib_*@bmHh>OtL6=E6MuZ}oM=+c6W?`V_sp3rAg1Q~`(FGHX1(FMh%HY* zhCKBpziR8y@4u_2$xBmx`7>MAV@;%O@4x?ttt-(3mNQHVe+Lh>hyC5hH&lIih2v0w z*?~XBIz+|)Sp1nvk2<4n$!**fOAv8ReOGv?z?*U6Lbes-*E z?bVuv&jtEM7j>-gm3rEC|L>!8GDPg$vGZ)rrjc&nw#^^tB0uT*UB!C~YB%Jckm?K# z`_7o4(kJjuJ^z+IefzB~<^MU~b82&=>E+^d5^#ur$A9IC1OM9mcQf{8zn(YT2XlOaA8EgPb28~R%>6Rd`Af}br*}^MPVWj1b~Sx9^pyGe;E`=V z9JHV6Onqm1abu5kTkGVS>x-v6`R=K|bP$0JN!Y+y21{<*s8DR)xTK3OuMSePASCt3QVw$5(AEq846U_kcCO$xzWTefN|@I83w!$aq#D8jekW+S2#lO31#a z0f;h%9lCR|c-}>Li>*KbBw)jieH((n|B54rsjLtfns z$=v;w4V;%RhF|P#vTS@TAEZcjUtDnZ7vb1}*c%rvg!cX|UcA1sy``aX+~dazV^<6H zwRaxBipRFREF3v-`HfG`{Vy-FcwJ*tlf0@m4MVJdZbr3}%PaOg+>rm|f4^*BzsjUs zfy3;>;i%=x+rCeJeA^OTT&HVkXNNQ@-HhZs`uqbP?xlA*L62Q_ibXqGp&NP=*eq^O9O`zjCtX$b1JNT10; zWdB}Vu*d*N#7M6P80jS}lcZ$TV~nbl{@N#{WsN7&?W>Yp; zaKmrtVi3`pRYGE`}^zOw$bWb%$ ziQnIwTGk;Z!)h6adRfb~kECc5r)t@f+G%gSE+g7?hafW)btanagbSWC8wvpy=MJ7_ ze*X6=v*Xv-bDs^N005u@I3ivu6K3IRcRqnoRX!i2C?b`tPRVR1@eDJ=Ap0$cjSY}N z&5Pm+P?Jx1c+#`6g*7&kICA0PL40khY-&E88iKVLV9peyYdMfz%0vi#dU_Q zMmKJXfgk6&EIhV=o1&={9FEpTqf@w8#e}IQWWVG%xp}#K8^3`Wl=$nnVy-$RGifWc z1|sd)BW@hHx{H`7l8B*Wz=KQA(uTNv#-nN&;1s2fiNXkOU|ayJ^VYLQ0MyPUVwFWQ zI4x?}P}87E3v&64-vTNos%fCG!H_rO#9f`PQI$(k=wx?5#L3zXM6~Q-1G=~b4qza0 zS6pY)b)|kPX_WXVt5>^>2Nyu&(P)VCcA*5|wc*3t0RV=fYf(8?rU`=Ck>7zLRJ2 z^OBG4DErHE<#>6wcuSysS8mjzT3TmSMO{;G)%%UhrdnB(Hbv7kUE9(2x98d`?cL!x zrJPDmHRmJF=bZoJT<6@z5uC&y!XLrc;m!Ed_#yly{2sTHdx+b^?dN{TJ+Sl(} z_r3V*{4M@a8hn@o2oM1RGXQ{gt%^Zzt(A!l3`XUQ$tFdCwzfYbhcxL7hmA%nji`}~ zdl}M?XaR!(1~3sMC=<}qSe}tHq)FkpoKadiH={rR7ZBhAfSKqRGt#gk2NSYK;0XXl z5LC{zw*X9K0P#sUfGAHC$Ym@yi-Z9xC{6%@o8Hy~svJC_DgcU}MW3rwnLA$LgwNvUxz3#2p?C`sQ&L@KfbuCpEVuVn)+ zhjp(fzo-4!{-8~`wf8zLOLi4T-q^x}{~Y!RldOBki-#E51D z;*5QQ98TCCQ2{$Uo1pePMKb*sCoXh;_T)L{mC%2)#{L4r`2e?10AWIs}%D7cM)J8`7>|HI{^-K~ z`~&!H3K+oF%eE4@@q&WUHr7jVs~o!Xm$uWAk~?8t!#gDsx?KU?rcI{f`L$dEW_&~la&8Am z@?1DTchW&s2!#$DCxBOj-R+$k(`GvWG<`}{qP6yBme=CKn9y4v0v#KsWYCFR#V!ye z1Sf3;Fb!4UYSuT2D?n$K1nAmpw*>LIEAO2N`+)>?E{Q4aRDUUN({FrChiA-lW#+*24fC;3RAro57J;ybWtb_Ui+n7tg40{LiL)*lc4T}1d;naJ(?vaQ{=>li%GA7sVy4m8M~!XD9q7PH{r;?nzlR$x#- z?_y{%R%AmC`U(f{^L`cd%*dzC+ih-}Z1yG3-LiP`(pHzfOU|^pW2R#N)25?*fT@bX#D>Bjl1R| zwHfh9A3UqLgI2Gvo_4rzaBN&MbJ_2seV5~}Q9>6-uvHla0{dp{-TB%r(XJ(Mk$YsY zYM<14e#X~hS3n>*B`03?@S%sWkn(g3(}%`X*o7o840lp5klv zx^}8*=nkC_vvSJkfz*EcK;<_&M6z|indvep%PAjL)Dn82dmse+eie>@n9v1#Wx%_rut1);n&qm>u9ID(=q6k#DK zcus&+PEBY`3h-j0zq4JXTJ2@m14PG|moJ;5X{Qsy`W#+I6i3t{8^Z2a9*B`pQk>~5gEur>|DYp{w5AMiy?&}b0 zGA5tI{`~9o%w3GkpS|@*zQGpk+i2ec?3*JFPm~++OVLP9v}V5ox~nmA{~B>v$!xc> z7;U@4;-z5bnutQn9Oe-;x5PwVJXv58m4U*}!xRu8fGsQVpN}Zkn;?(;j919PMqsX@ zQ8|DEY&p|fKM{7mlgr)ti#?_9YOan>oT!#V4@a`JLQp)x@A64!wo64J}ETfgGJqe5F)r{N;AKFDTj8uSL1Uy zwA&et&*{)^_%-WN0}$d8kB5ID;|qcdadL?UmSy77!OAXjiH=~=brMP zfL5=C$LD8;-R?-_77-kCGehZ@t5S4biNGhmHH&_UKn?YZCRe&ehX{Y8iG++2)UJ3t zj4oG;PFw(s{&fZ3jr+)r^A|@kR3xF9jtB?Ea>nSVi@9$YT-}18go5d?&TY|UPFmy) zWvZirs~H=wefj+$e)sy<9_Jtpsi0}65+af!bCCz({78enTM*tv1zaM;nP?OEEpl+- z>ZndzVdFWAqjJ{v@PlHz^i7&B-7P6m4U{6h#2jPcS<%GCL)|jbq3k&t`Z{XFI%uZ0 zpJE{pivnmm0gh<+vXw=qQsjSK*rhieL@MnPhjw!z zj!S8#J$rk*w-irciA2onjU}uKNRknT@cGryFEtWI!e$ytS9c>Z zpI=d!2BNT#oJ4D)!#`qNPWHFN$SKJ53AMEk2EFz_9}WcHa=ULyYZpJJJ)zz@LAdo+ zUr*&txE|>QmJ1<|8_H`6J#I8!jV}pM&Mb-${H3d>06#%ysF^yVTF9zD$Qz$ zw=+g0;v^-=5sBt0%cUdWtU*|yf=}yv65wlsd_|bkc<)B zKx9dc^{DrQN=qkaJ$sJP#%VtP<-@b^)7JV?OJzGE&)s8$Bb^(xjKwgD_8^5}>Fn!} z7RqEoE0|7#FeBKPXdWC13#Tm5wC*cb%E60cd;)cX1-m-LLa$nY-G#9OZg;>sZX2^( zEI-`t^qVd+wKJ)7@^edzn)ea0S{lq{WcA=Le!u^hP97G<4Rfe)J*~7Grt@_~rqoZ@ zFDfdI9(|!&*6MLLxMKG9d$0C5kG^rDZwa%)1U`MaD@Hn(v`qFxkN0u(_I-?+F3$X! z<2^8@z*-GWUB#R{Kb{dYXG^B#xUJhUW|723Kw{x%205rX^N%&pEE@qJ| zpUvmT<3C4!42KDVoBlhS^%b{btyAr%r|;`xn8icS%{6PzocUMJQfA+G+UBfY4|?xNGi80s-MeEJcw)>?`o?XX8z;_Px+~5Jl6CB7FFRLhgO9VhW~F=A3uA!U}Jnj^|FB z>73KT!6*vD^cZdd+=}Bs5=mS@YG`mswX4SEkzOxJ21u9J>mtPIDEi=4Q*W-5QBK*M zhcR34QZI@x?*TovT2QG#K!dpn1X4;Uq^v6F#YqPa2I$6)lJ2M_=efg+$z-X&(_)c8 zAVQ5RaPg9r(~r6DnFHQzg>GC^FvJ`Ei!Vn{oOtc%GRELm*La#M>IXR0#7Hw_A5URe z6^2nbe)~?5P~L11PMIQEFuBCaE*8h6CW(p$^CA(RkK;Hc6xArfT=4zOO}OuUvR;yO zkfb-A9y2)YHby&D^K;NG^@x-gyt{Kx3oWLF&6h^uogboCQdS!5 z(JnC1;4ON!tmDa*#Q^&8a1J*wahPt7GeVeNUM{WI)NR=#2RpXdc{tEQy(E^XY(5rr zqjsR*6?}hS=*(cP$2*kzZy<f5&+Pk01)`@QF`0@L`kO=K*aX5dtz~l49AG-2TI$o zIxGnfH7A)0N7Xc%AdAJYbvjLhGaUmnTYGhF*-j9V;ewesc7tm>K#m60!Azw%uHJ*g z@-W&oRM>+PqmKb{ktFTvB5G%I>?fVt!cl3zn3WTLJrRt=`%>6f0lF>48E0!}NY+r^ z3h-t%6D}#Dz<-Uve^lD^xfK=|SE5yxqD@I-86OBkf*ge~GY)rnmCIY@5-do}1>h3U zhY>urVN`*~!z?qkmt*E|p1F>fv32J{3V{$3VG>+4JeKj|;UakMS>wiuAY2R)VBrTS z3drzy@Srq2f#RUzxlr(eMO53tXpdc5G&ATR@NW2Lk@N}F?%>wG<+h)wTkRT4W0xIT zZMDU^Q0^%m40cfdq}AXWTQz^#?KbIUb?087&Qc3T=&Q6KLz~P|x#hXGlGv=yAnI$e z!+x{`W}8W((tHawYtdnb1FkoNFuZQsV!I_e)m=7CQyVV(H~HA@Nxcm|Wt+7lZo9OA a!Vc~9U7SGB8$q3Ii#9CnAx#qS0RRAsKuhfa literal 0 HcmV?d00001 diff --git a/assets/style.ca30dd5f.css b/assets/style.ca30dd5f.css new file mode 100644 index 00000000..e0a02a58 --- /dev/null +++ b/assets/style.ca30dd5f.css @@ -0,0 +1 @@ +@charset "UTF-8";@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-cyrillic.5f2c6c8c.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-cyrillic-ext.e75737ce.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-greek.d5a6d92a.woff2) format("woff2");unicode-range:U+0370-03FF}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-greek-ext.ab0619bc.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-latin.2ed14f66.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-latin-ext.0030eebd.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:normal;font-named-instance:"Regular";src:url(/zerdocs/assets/inter-roman-vietnamese.14ce25a6.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-cyrillic.ea42a392.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-cyrillic-ext.33bd5a8e.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-greek.8f4463c4.woff2) format("woff2");unicode-range:U+0370-03FF}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-greek-ext.4fbe9427.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-latin.bd3b6f56.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-latin-ext.bd8920cc.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter var;font-weight:100 900;font-display:swap;font-style:italic;font-named-instance:"Italic";src:url(/zerdocs/assets/inter-italic-vietnamese.6ce511fb.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+1EA0-1EF9,U+20AB}@font-face{font-family:Chinese Quotes;src:local("PingFang SC Regular"),local("PingFang SC"),local("SimHei"),local("Source Han Sans SC");unicode-range:U+2018,U+2019,U+201C,U+201D}:root{--vp-c-white: #ffffff;--vp-c-black: #000000;--vp-c-neutral: var(--vp-c-black);--vp-c-neutral-inverse: var(--vp-c-white)}.dark{--vp-c-neutral: var(--vp-c-white);--vp-c-neutral-inverse: var(--vp-c-black)}:root{--vp-c-gray-1: #dddde3;--vp-c-gray-2: #e4e4e9;--vp-c-gray-3: #ebebef;--vp-c-gray-soft: rgba(142, 150, 170, .14);--vp-c-indigo-1: #3451b2;--vp-c-indigo-2: #3a5ccc;--vp-c-indigo-3: #5672cd;--vp-c-indigo-soft: rgba(100, 108, 255, .14);--vp-c-green-1: #18794e;--vp-c-green-2: #299764;--vp-c-green-3: #30a46c;--vp-c-green-soft: rgba(16, 185, 129, .14);--vp-c-yellow-1: #915930;--vp-c-yellow-2: #946300;--vp-c-yellow-3: #9f6a00;--vp-c-yellow-soft: rgba(234, 179, 8, .14);--vp-c-red-1: #b8272c;--vp-c-red-2: #d5393e;--vp-c-red-3: #e0575b;--vp-c-red-soft: rgba(244, 63, 94, .14);--vp-c-sponsor: #db2777}.dark{--vp-c-gray-1: #515c67;--vp-c-gray-2: #414853;--vp-c-gray-3: #32363f;--vp-c-gray-soft: rgba(101, 117, 133, .16);--vp-c-indigo-1: #a8b1ff;--vp-c-indigo-2: #5c73e7;--vp-c-indigo-3: #3e63dd;--vp-c-indigo-soft: rgba(100, 108, 255, .16);--vp-c-green-1: #3dd68c;--vp-c-green-2: #30a46c;--vp-c-green-3: #298459;--vp-c-green-soft: rgba(16, 185, 129, .16);--vp-c-yellow-1: #f9b44e;--vp-c-yellow-2: #da8b17;--vp-c-yellow-3: #a46a0a;--vp-c-yellow-soft: rgba(234, 179, 8, .16);--vp-c-red-1: #f66f81;--vp-c-red-2: #f14158;--vp-c-red-3: #b62a3c;--vp-c-red-soft: rgba(244, 63, 94, .16)}:root{--vp-c-bg: #ffffff;--vp-c-bg-alt: #f6f6f7;--vp-c-bg-elv: #ffffff;--vp-c-bg-soft: #f6f6f7}.dark{--vp-c-bg: #1b1b1f;--vp-c-bg-alt: #161618;--vp-c-bg-elv: #202127;--vp-c-bg-soft: #202127}:root{--vp-c-border: #c2c2c4;--vp-c-divider: #e2e2e3;--vp-c-gutter: #e2e2e3}.dark{--vp-c-border: #3c3f44;--vp-c-divider: #2e2e32;--vp-c-gutter: #000000}:root{--vp-c-text-1: rgba(60, 60, 67);--vp-c-text-2: rgba(60, 60, 67, .78);--vp-c-text-3: rgba(60, 60, 67, .56)}.dark{--vp-c-text-1: rgba(255, 255, 245, .86);--vp-c-text-2: rgba(235, 235, 245, .6);--vp-c-text-3: rgba(235, 235, 245, .38)}:root{--vp-c-default-1: var(--vp-c-gray-1);--vp-c-default-2: var(--vp-c-gray-2);--vp-c-default-3: var(--vp-c-gray-3);--vp-c-default-soft: var(--vp-c-gray-soft);--vp-c-brand-1: var(--vp-c-indigo-1);--vp-c-brand-2: var(--vp-c-indigo-2);--vp-c-brand-3: var(--vp-c-indigo-3);--vp-c-brand-soft: var(--vp-c-indigo-soft);--vp-c-brand: var(--vp-c-brand-1);--vp-c-tip-1: var(--vp-c-brand-1);--vp-c-tip-2: var(--vp-c-brand-2);--vp-c-tip-3: var(--vp-c-brand-3);--vp-c-tip-soft: var(--vp-c-brand-soft);--vp-c-warning-1: var(--vp-c-yellow-1);--vp-c-warning-2: var(--vp-c-yellow-2);--vp-c-warning-3: var(--vp-c-yellow-3);--vp-c-warning-soft: var(--vp-c-yellow-soft);--vp-c-danger-1: var(--vp-c-red-1);--vp-c-danger-2: var(--vp-c-red-2);--vp-c-danger-3: var(--vp-c-red-3);--vp-c-danger-soft: var(--vp-c-red-soft)}:root{--vp-font-family-base: "Chinese Quotes", "Inter var", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--vp-font-family-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}:root{--vp-shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06);--vp-shadow-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07);--vp-shadow-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);--vp-shadow-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12);--vp-shadow-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16)}:root{--vp-z-index-footer: 10;--vp-z-index-local-nav: 20;--vp-z-index-nav: 30;--vp-z-index-layout-top: 40;--vp-z-index-backdrop: 50;--vp-z-index-sidebar: 60}:root{--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E");--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E")}:root{--vp-layout-max-width: 1440px}:root{--vp-header-anchor-symbol: "#"}:root{--vp-code-line-height: 1.7;--vp-code-font-size: .875em;--vp-code-color: var(--vp-c-brand-1);--vp-code-link-color: var(--vp-c-brand-1);--vp-code-link-hover-color: var(--vp-c-brand-2);--vp-code-bg: var(--vp-c-default-soft);--vp-code-block-color: var(--vp-c-text-2);--vp-code-block-bg: var(--vp-c-bg-alt);--vp-code-block-divider-color: var(--vp-c-gutter);--vp-code-lang-color: var(--vp-c-text-3);--vp-code-line-highlight-color: var(--vp-c-default-soft);--vp-code-line-number-color: var(--vp-c-text-3);--vp-code-line-diff-add-color: var(--vp-c-green-soft);--vp-code-line-diff-add-symbol-color: var(--vp-c-green-1);--vp-code-line-diff-remove-color: var(--vp-c-red-soft);--vp-code-line-diff-remove-symbol-color: var(--vp-c-red-1);--vp-code-line-warning-color: var(--vp-c-yellow-soft);--vp-code-line-error-color: var(--vp-c-red-soft);--vp-code-copy-code-border-color: var(--vp-c-divider);--vp-code-copy-code-bg: var(--vp-c-bg-soft);--vp-code-copy-code-hover-border-color: var(--vp-c-divider);--vp-code-copy-code-hover-bg: var(--vp-c-bg);--vp-code-copy-code-active-text: var(--vp-c-text-2);--vp-code-copy-copied-text-content: "Copied";--vp-code-tab-divider: var(--vp-code-block-divider-color);--vp-code-tab-text-color: var(--vp-c-text-2);--vp-code-tab-bg: var(--vp-code-block-bg);--vp-code-tab-hover-text-color: var(--vp-c-text-1);--vp-code-tab-active-text-color: var(--vp-c-text-1);--vp-code-tab-active-bar-color: var(--vp-c-brand-1)}:root{--vp-button-brand-border: transparent;--vp-button-brand-text: var(--vp-c-white);--vp-button-brand-bg: var(--vp-c-brand-3);--vp-button-brand-hover-border: transparent;--vp-button-brand-hover-text: var(--vp-c-white);--vp-button-brand-hover-bg: var(--vp-c-brand-2);--vp-button-brand-active-border: transparent;--vp-button-brand-active-text: var(--vp-c-white);--vp-button-brand-active-bg: var(--vp-c-brand-1);--vp-button-alt-border: transparent;--vp-button-alt-text: var(--vp-c-text-1);--vp-button-alt-bg: var(--vp-c-default-3);--vp-button-alt-hover-border: transparent;--vp-button-alt-hover-text: var(--vp-c-text-1);--vp-button-alt-hover-bg: var(--vp-c-default-2);--vp-button-alt-active-border: transparent;--vp-button-alt-active-text: var(--vp-c-text-1);--vp-button-alt-active-bg: var(--vp-c-default-1);--vp-button-sponsor-border: var(--vp-c-text-2);--vp-button-sponsor-text: var(--vp-c-text-2);--vp-button-sponsor-bg: transparent;--vp-button-sponsor-hover-border: var(--vp-c-sponsor);--vp-button-sponsor-hover-text: var(--vp-c-sponsor);--vp-button-sponsor-hover-bg: transparent;--vp-button-sponsor-active-border: var(--vp-c-sponsor);--vp-button-sponsor-active-text: var(--vp-c-sponsor);--vp-button-sponsor-active-bg: transparent}:root{--vp-custom-block-font-size: 14px;--vp-custom-block-code-font-size: 13px;--vp-custom-block-info-border: transparent;--vp-custom-block-info-text: var(--vp-c-text-1);--vp-custom-block-info-bg: var(--vp-c-default-soft);--vp-custom-block-info-code-bg: var(--vp-c-default-soft);--vp-custom-block-tip-border: transparent;--vp-custom-block-tip-text: var(--vp-c-text-1);--vp-custom-block-tip-bg: var(--vp-c-brand-soft);--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);--vp-custom-block-warning-border: transparent;--vp-custom-block-warning-text: var(--vp-c-text-1);--vp-custom-block-warning-bg: var(--vp-c-warning-soft);--vp-custom-block-warning-code-bg: var(--vp-c-warning-soft);--vp-custom-block-danger-border: transparent;--vp-custom-block-danger-text: var(--vp-c-text-1);--vp-custom-block-danger-bg: var(--vp-c-danger-soft);--vp-custom-block-danger-code-bg: var(--vp-c-danger-soft);--vp-custom-block-details-border: var(--vp-custom-block-info-border);--vp-custom-block-details-text: var(--vp-custom-block-info-text);--vp-custom-block-details-bg: var(--vp-custom-block-info-bg);--vp-custom-block-details-code-bg: var(--vp-custom-block-info-code-bg)}:root{--vp-input-border-color: var(--vp-c-border);--vp-input-bg-color: var(--vp-c-bg-alt);--vp-input-switch-bg-color: var(--vp-c-gray-soft)}:root{--vp-nav-height: 64px;--vp-nav-bg-color: var(--vp-c-bg);--vp-nav-screen-bg-color: var(--vp-c-bg);--vp-nav-logo-height: 24px}.hide-nav{--vp-nav-height: 0px}.hide-nav .VPSidebar{--vp-nav-height: 22px}:root{--vp-local-nav-bg-color: var(--vp-c-bg)}:root{--vp-sidebar-width: 272px;--vp-sidebar-bg-color: var(--vp-c-bg-alt)}:root{--vp-backdrop-bg-color: rgba(0, 0, 0, .6)}:root{--vp-home-hero-name-color: var(--vp-c-brand-1);--vp-home-hero-name-background: transparent;--vp-home-hero-image-background-image: none;--vp-home-hero-image-filter: none}:root{--vp-badge-info-border: transparent;--vp-badge-info-text: var(--vp-c-text-2);--vp-badge-info-bg: var(--vp-c-default-soft);--vp-badge-tip-border: transparent;--vp-badge-tip-text: var(--vp-c-brand-1);--vp-badge-tip-bg: var(--vp-c-brand-soft);--vp-badge-warning-border: transparent;--vp-badge-warning-text: var(--vp-c-warning-1);--vp-badge-warning-bg: var(--vp-c-warning-soft);--vp-badge-danger-border: transparent;--vp-badge-danger-text: var(--vp-c-danger-1);--vp-badge-danger-bg: var(--vp-c-danger-soft)}:root{--vp-carbon-ads-text-color: var(--vp-c-text-1);--vp-carbon-ads-poweredby-color: var(--vp-c-text-2);--vp-carbon-ads-bg-color: var(--vp-c-bg-soft);--vp-carbon-ads-hover-text-color: var(--vp-c-brand-1);--vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1)}:root{--vp-local-search-bg: var(--vp-c-bg);--vp-local-search-result-bg: var(--vp-c-bg);--vp-local-search-result-border: var(--vp-c-divider);--vp-local-search-result-selected-bg: var(--vp-c-bg);--vp-local-search-result-selected-border: var(--vp-c-brand-1);--vp-local-search-highlight-bg: var(--vp-c-brand-1);--vp-local-search-highlight-text: var(--vp-c-neutral-inverse)}@media (prefers-reduced-motion: reduce){*,:before,:after{animation-delay:-1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important;background-attachment:initial!important;scroll-behavior:auto!important;transition-duration:0s!important;transition-delay:0s!important}}*,:before,:after{box-sizing:border-box}html{line-height:1.4;font-size:16px;-webkit-text-size-adjust:100%}html.dark{color-scheme:dark}body{margin:0;width:100%;min-width:320px;min-height:100vh;line-height:24px;font-family:var(--vp-font-family-base);font-size:16px;font-weight:400;color:var(--vp-c-text-1);background-color:var(--vp-c-bg);direction:ltr;font-synthesis:style;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}main{display:block}h1,h2,h3,h4,h5,h6{margin:0;line-height:24px;font-size:16px;font-weight:400}p{margin:0}strong,b{font-weight:600}a,area,button,[role=button],input,label,select,summary,textarea{touch-action:manipulation}a{color:inherit;text-decoration:inherit}ol,ul{list-style:none;margin:0;padding:0}blockquote{margin:0}pre,code,kbd,samp{font-family:var(--vp-font-family-mono)}img,svg,video,canvas,audio,iframe,embed,object{display:block}figure{margin:0}img,video{max-width:100%;height:auto}button,input,optgroup,select,textarea{border:0;padding:0;line-height:inherit;color:inherit}button{padding:0;font-family:inherit;background-color:transparent;background-image:none}button:enabled,[role=button]:enabled{cursor:pointer}button:focus,button:focus-visible{outline:1px dotted;outline:4px auto -webkit-focus-ring-color}button:focus:not(:focus-visible){outline:none!important}input:focus,textarea:focus,select:focus{outline:none}table{border-collapse:collapse}input{background-color:transparent}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:var(--vp-c-text-3)}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:var(--vp-c-text-3)}input::placeholder,textarea::placeholder{color:var(--vp-c-text-3)}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield}textarea{resize:vertical}select{-webkit-appearance:none}fieldset{margin:0;padding:0}h1,h2,h3,h4,h5,h6,li,p{overflow-wrap:break-word}vite-error-overlay{z-index:9999}mjx-container{display:inline-block;margin:auto 2px -2px}mjx-container>svg{margin:auto}.visually-hidden{position:absolute;width:1px;height:1px;white-space:nowrap;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}.custom-block{border:1px solid transparent;border-radius:8px;padding:16px 16px 8px;line-height:24px;font-size:var(--vp-custom-block-font-size);color:var(--vp-c-text-2)}.custom-block.info{border-color:var(--vp-custom-block-info-border);color:var(--vp-custom-block-info-text);background-color:var(--vp-custom-block-info-bg)}.custom-block.info a,.custom-block.info code{color:var(--vp-c-brand-1)}.custom-block.info a:hover{color:var(--vp-c-brand-2)}.custom-block.info code{background-color:var(--vp-custom-block-info-code-bg)}.custom-block.tip{border-color:var(--vp-custom-block-tip-border);color:var(--vp-custom-block-tip-text);background-color:var(--vp-custom-block-tip-bg)}.custom-block.tip a,.custom-block.tip code{color:var(--vp-c-brand-1)}.custom-block.tip a:hover{color:var(--vp-c-brand-2)}.custom-block.tip code{background-color:var(--vp-custom-block-tip-code-bg)}.custom-block.warning{border-color:var(--vp-custom-block-warning-border);color:var(--vp-custom-block-warning-text);background-color:var(--vp-custom-block-warning-bg)}.custom-block.warning a,.custom-block.warning code{color:var(--vp-c-warning-1)}.custom-block.warning a:hover{color:var(--vp-c-warning-2)}.custom-block.warning code{background-color:var(--vp-custom-block-warning-code-bg)}.custom-block.danger{border-color:var(--vp-custom-block-danger-border);color:var(--vp-custom-block-danger-text);background-color:var(--vp-custom-block-danger-bg)}.custom-block.danger a,.custom-block.danger code{color:var(--vp-c-danger-1)}.custom-block.danger a:hover{color:var(--vp-c-danger-2)}.custom-block.danger code{background-color:var(--vp-custom-block-danger-code-bg)}.custom-block.details{border-color:var(--vp-custom-block-details-border);color:var(--vp-custom-block-details-text);background-color:var(--vp-custom-block-details-bg)}.custom-block.details a{color:var(--vp-c-brand-1)}.custom-block.details a:hover{color:var(--vp-c-brand-2)}.custom-block.details code{background-color:var(--vp-custom-block-details-code-bg)}.custom-block-title{font-weight:600}.custom-block p+p{margin:8px 0}.custom-block.details summary{margin:0 0 8px;font-weight:700;cursor:pointer}.custom-block.details summary+p{margin:8px 0}.custom-block a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px;transition:opacity .25s}.custom-block a:hover{opacity:.75}.custom-block code{font-size:var(--vp-custom-block-code-font-size)}.custom-block.custom-block th,.custom-block.custom-block blockquote>p{font-size:var(--vp-custom-block-font-size);color:inherit}.dark .vp-code-light{display:none}html:not(.dark) .vp-code-dark{display:none}.vp-code-group{margin-top:16px}.vp-code-group .tabs{position:relative;display:flex;margin-right:-24px;margin-left:-24px;padding:0 12px;background-color:var(--vp-code-tab-bg);overflow-x:auto;overflow-y:hidden;box-shadow:inset 0 -1px var(--vp-code-tab-divider)}@media (min-width: 640px){.vp-code-group .tabs{margin-right:0;margin-left:0;border-radius:8px 8px 0 0}}.vp-code-group .tabs input{position:fixed;opacity:0;pointer-events:none}.vp-code-group .tabs label{position:relative;display:inline-block;border-bottom:1px solid transparent;padding:0 12px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-code-tab-text-color);white-space:nowrap;cursor:pointer;transition:color .25s}.vp-code-group .tabs label:after{position:absolute;right:8px;bottom:-1px;left:8px;z-index:1;height:2px;border-radius:2px;content:"";background-color:transparent;transition:background-color .25s}.vp-code-group label:hover{color:var(--vp-code-tab-hover-text-color)}.vp-code-group input:checked+label{color:var(--vp-code-tab-active-text-color)}.vp-code-group input:checked+label:after{background-color:var(--vp-code-tab-active-bar-color)}.vp-code-group div[class*=language-],.vp-block{display:none;margin-top:0!important;border-top-left-radius:0!important;border-top-right-radius:0!important}.vp-code-group div[class*=language-].active,.vp-block.active{display:block}.vp-block{padding:20px 24px}.vp-doc h1,.vp-doc h2,.vp-doc h3,.vp-doc h4,.vp-doc h5,.vp-doc h6{position:relative;font-weight:600;outline:none}.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:28px}.vp-doc h2{margin:48px 0 16px;border-top:1px solid var(--vp-c-divider);padding-top:24px;letter-spacing:-.02em;line-height:32px;font-size:24px}.vp-doc h3{margin:32px 0 0;letter-spacing:-.01em;line-height:28px;font-size:20px}.vp-doc .header-anchor{position:absolute;top:0;left:0;margin-left:-.87em;font-weight:500;-webkit-user-select:none;user-select:none;opacity:0;text-decoration:none;transition:color .25s,opacity .25s}.vp-doc .header-anchor:before{content:var(--vp-header-anchor-symbol)}.vp-doc h1:hover .header-anchor,.vp-doc h1 .header-anchor:focus,.vp-doc h2:hover .header-anchor,.vp-doc h2 .header-anchor:focus,.vp-doc h3:hover .header-anchor,.vp-doc h3 .header-anchor:focus,.vp-doc h4:hover .header-anchor,.vp-doc h4 .header-anchor:focus,.vp-doc h5:hover .header-anchor,.vp-doc h5 .header-anchor:focus,.vp-doc h6:hover .header-anchor,.vp-doc h6 .header-anchor:focus{opacity:1}@media (min-width: 768px){.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:32px}}.vp-doc h2 .header-anchor{top:24px}.vp-doc p,.vp-doc summary{margin:16px 0}.vp-doc p{line-height:28px}.vp-doc blockquote{margin:16px 0;border-left:2px solid var(--vp-c-divider);padding-left:16px;transition:border-color .5s}.vp-doc blockquote>p{margin:0;font-size:16px;color:var(--vp-c-text-2);transition:color .5s}.vp-doc a{font-weight:500;color:var(--vp-c-brand-1);text-decoration:underline;text-underline-offset:2px;transition:color .25s,opacity .25s}.vp-doc a:hover{color:var(--vp-c-brand-2)}.vp-doc strong{font-weight:600}.vp-doc ul,.vp-doc ol{padding-left:1.25rem;margin:16px 0}.vp-doc ul{list-style:disc}.vp-doc ol{list-style:decimal}.vp-doc li+li{margin-top:8px}.vp-doc li>ol,.vp-doc li>ul{margin:8px 0 0}.vp-doc table{display:block;border-collapse:collapse;margin:20px 0;overflow-x:auto}.vp-doc tr{border-top:1px solid var(--vp-c-divider);transition:background-color .5s}.vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}.vp-doc th,.vp-doc td{border:1px solid var(--vp-c-divider);padding:8px 16px}.vp-doc th{text-align:left;font-size:14px;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-doc td{font-size:14px}.vp-doc hr{margin:16px 0;border:none;border-top:1px solid var(--vp-c-divider)}.vp-doc .custom-block{margin:16px 0}.vp-doc .custom-block p{margin:8px 0;line-height:24px}.vp-doc .custom-block p:first-child{margin:0}.vp-doc .custom-block div[class*=language-]{margin:8px 0;border-radius:8px}.vp-doc .custom-block div[class*=language-] code{font-weight:400;background-color:transparent}.vp-doc .custom-block .vp-code-group .tabs{margin:0;border-radius:8px 8px 0 0}.vp-doc :not(pre,h1,h2,h3,h4,h5,h6)>code{font-size:var(--vp-code-font-size);color:var(--vp-code-color)}.vp-doc :not(pre)>code{border-radius:4px;padding:3px 6px;background-color:var(--vp-code-bg);transition:color .25s,background-color .5s}.vp-doc a>code{color:var(--vp-code-link-color)}.vp-doc a:hover>code{color:var(--vp-code-link-hover-color)}.vp-doc h1>code,.vp-doc h2>code,.vp-doc h3>code{font-size:.9em}.vp-doc div[class*=language-],.vp-block{position:relative;margin:16px -24px;background-color:var(--vp-code-block-bg);overflow-x:auto;transition:background-color .5s}@media (min-width: 640px){.vp-doc div[class*=language-],.vp-block{border-radius:8px;margin:16px 0}}@media (max-width: 639px){.vp-doc li div[class*=language-]{border-radius:8px 0 0 8px}}.vp-doc div[class*=language-]+div[class*=language-],.vp-doc div[class$=-api]+div[class*=language-],.vp-doc div[class*=language-]+div[class$=-api]>div[class*=language-]{margin-top:-8px}.vp-doc [class*=language-] pre,.vp-doc [class*=language-] code{direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.vp-doc [class*=language-] pre{position:relative;z-index:1;margin:0;padding:20px 0;background:transparent;overflow-x:auto}.vp-doc [class*=language-] code{display:block;padding:0 24px;width:fit-content;min-width:100%;line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-block-color);transition:color .5s}.vp-doc [class*=language-] code .highlighted{background-color:var(--vp-code-line-highlight-color);transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .highlighted.error{background-color:var(--vp-code-line-error-color)}.vp-doc [class*=language-] code .highlighted.warning{background-color:var(--vp-code-line-warning-color)}.vp-doc [class*=language-] code .diff{transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .diff:before{position:absolute;left:10px}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){filter:blur(.095rem);opacity:.4;transition:filter .35s,opacity .35s}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){opacity:.7;transition:filter .35s,opacity .35s}.vp-doc [class*=language-]:hover .has-focused-lines .line:not(.has-focus){filter:blur(0);opacity:1}.vp-doc [class*=language-] code .diff.remove{background-color:var(--vp-code-line-diff-remove-color);opacity:.7}.vp-doc [class*=language-] code .diff.remove:before{content:"-";color:var(--vp-code-line-diff-remove-symbol-color)}.vp-doc [class*=language-] code .diff.add{background-color:var(--vp-code-line-diff-add-color)}.vp-doc [class*=language-] code .diff.add:before{content:"+";color:var(--vp-code-line-diff-add-symbol-color)}.vp-doc div[class*=language-].line-numbers-mode{padding-left:32px}.vp-doc .line-numbers-wrapper{position:absolute;top:0;bottom:0;left:0;z-index:3;border-right:1px solid var(--vp-code-block-divider-color);padding-top:20px;width:32px;text-align:center;font-family:var(--vp-font-family-mono);line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-line-number-color);transition:border-color .5s,color .5s}.vp-doc [class*=language-]>button.copy{direction:ltr;position:absolute;top:12px;right:12px;z-index:3;border:1px solid var(--vp-code-copy-code-border-color);border-radius:4px;width:40px;height:40px;background-color:var(--vp-code-copy-code-bg);opacity:0;cursor:pointer;background-image:var(--vp-icon-copy);background-position:50%;background-size:20px;background-repeat:no-repeat;transition:border-color .25s,background-color .25s,opacity .25s}.vp-doc [class*=language-]:hover>button.copy,.vp-doc [class*=language-]>button.copy:focus{opacity:1}.vp-doc [class*=language-]>button.copy:hover,.vp-doc [class*=language-]>button.copy.copied{border-color:var(--vp-code-copy-code-hover-border-color);background-color:var(--vp-code-copy-code-hover-bg)}.vp-doc [class*=language-]>button.copy.copied,.vp-doc [class*=language-]>button.copy:hover.copied{border-radius:0 4px 4px 0;background-color:var(--vp-code-copy-code-hover-bg);background-image:var(--vp-icon-copied)}.vp-doc [class*=language-]>button.copy.copied:before,.vp-doc [class*=language-]>button.copy:hover.copied:before{position:relative;top:-1px;transform:translate(calc(-100% - 1px));display:flex;justify-content:center;align-items:center;border:1px solid var(--vp-code-copy-code-hover-border-color);border-right:0;border-radius:4px 0 0 4px;padding:0 10px;width:fit-content;height:40px;text-align:center;font-size:12px;font-weight:500;color:var(--vp-code-copy-code-active-text);background-color:var(--vp-code-copy-code-hover-bg);white-space:nowrap;content:var(--vp-code-copy-copied-text-content)}.vp-doc [class*=language-]>span.lang{position:absolute;top:2px;right:8px;z-index:2;font-size:12px;font-weight:500;color:var(--vp-code-lang-color);transition:color .4s,opacity .4s}.vp-doc [class*=language-]:hover>button.copy+span.lang,.vp-doc [class*=language-]>button.copy:focus+span.lang{opacity:0}.vp-doc .VPTeamMembers{margin-top:24px}.vp-doc .VPTeamMembers.small.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}.vp-doc .VPTeamMembers.small.count-2 .container,.vp-doc .VPTeamMembers.small.count-3 .container{max-width:100%!important}.vp-doc .VPTeamMembers.medium.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}:is(.vp-external-link-icon,.vp-doc a[href*="://"],.vp-doc a[target=_blank]):not(.no-icon):after{display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.vp-external-link-icon:after{content:""}.vp-sponsor{border-radius:16px;overflow:hidden}.vp-sponsor.aside{border-radius:12px}.vp-sponsor-section+.vp-sponsor-section{margin-top:4px}.vp-sponsor-tier{margin-bottom:4px;text-align:center;letter-spacing:1px;line-height:24px;width:100%;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-sponsor.normal .vp-sponsor-tier{padding:13px 0 11px;font-size:14px}.vp-sponsor.aside .vp-sponsor-tier{padding:9px 0 7px;font-size:12px}.vp-sponsor-grid+.vp-sponsor-tier{margin-top:4px}.vp-sponsor-grid{display:flex;flex-wrap:wrap;gap:4px}.vp-sponsor-grid.xmini .vp-sponsor-grid-link{height:64px}.vp-sponsor-grid.xmini .vp-sponsor-grid-image{max-width:64px;max-height:22px}.vp-sponsor-grid.mini .vp-sponsor-grid-link{height:72px}.vp-sponsor-grid.mini .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.small .vp-sponsor-grid-link{height:96px}.vp-sponsor-grid.small .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.medium .vp-sponsor-grid-link{height:112px}.vp-sponsor-grid.medium .vp-sponsor-grid-image{max-width:120px;max-height:36px}.vp-sponsor-grid.big .vp-sponsor-grid-link{height:184px}.vp-sponsor-grid.big .vp-sponsor-grid-image{max-width:192px;max-height:56px}.vp-sponsor-grid[data-vp-grid="2"] .vp-sponsor-grid-item{width:calc((100% - 4px)/2)}.vp-sponsor-grid[data-vp-grid="3"] .vp-sponsor-grid-item{width:calc((100% - 4px * 2) / 3)}.vp-sponsor-grid[data-vp-grid="4"] .vp-sponsor-grid-item{width:calc((100% - 12px)/4)}.vp-sponsor-grid[data-vp-grid="5"] .vp-sponsor-grid-item{width:calc((100% - 16px)/5)}.vp-sponsor-grid[data-vp-grid="6"] .vp-sponsor-grid-item{width:calc((100% - 4px * 5) / 6)}.vp-sponsor-grid-item{flex-shrink:0;width:100%;background-color:var(--vp-c-bg-soft);transition:background-color .25s}.vp-sponsor-grid-item:hover{background-color:var(--vp-c-default-soft)}.vp-sponsor-grid-item:hover .vp-sponsor-grid-image{filter:grayscale(0) invert(0)}.vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.dark .vp-sponsor-grid-item:hover{background-color:var(--vp-c-white)}.dark .vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.vp-sponsor-grid-link{display:flex}.vp-sponsor-grid-box{display:flex;justify-content:center;align-items:center;width:100%}.vp-sponsor-grid-image{max-width:100%;filter:grayscale(1);transition:filter .25s}.dark .vp-sponsor-grid-image{filter:grayscale(1) invert(1)}.VPBadge[data-v-9613cc9f]{display:inline-block;margin-left:2px;border:1px solid transparent;border-radius:12px;padding:0 10px;line-height:22px;font-size:12px;font-weight:500;transform:translateY(-2px)}.vp-doc h1>.VPBadge[data-v-9613cc9f]{margin-top:4px;vertical-align:top}.vp-doc h2>.VPBadge[data-v-9613cc9f]{margin-top:3px;padding:0 8px;vertical-align:top}.vp-doc h3>.VPBadge[data-v-9613cc9f]{vertical-align:middle}.vp-doc h4>.VPBadge[data-v-9613cc9f],.vp-doc h5>.VPBadge[data-v-9613cc9f],.vp-doc h6>.VPBadge[data-v-9613cc9f]{vertical-align:middle;line-height:18px}.VPBadge.info[data-v-9613cc9f]{border-color:var(--vp-badge-info-border);color:var(--vp-badge-info-text);background-color:var(--vp-badge-info-bg)}.VPBadge.tip[data-v-9613cc9f]{border-color:var(--vp-badge-tip-border);color:var(--vp-badge-tip-text);background-color:var(--vp-badge-tip-bg)}.VPBadge.warning[data-v-9613cc9f]{border-color:var(--vp-badge-warning-border);color:var(--vp-badge-warning-text);background-color:var(--vp-badge-warning-bg)}.VPBadge.danger[data-v-9613cc9f]{border-color:var(--vp-badge-danger-border);color:var(--vp-badge-danger-text);background-color:var(--vp-badge-danger-bg)}.VPBackdrop[data-v-c79a1216]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vp-z-index-backdrop);background:var(--vp-backdrop-bg-color);transition:opacity .5s}.VPBackdrop.fade-enter-from[data-v-c79a1216],.VPBackdrop.fade-leave-to[data-v-c79a1216]{opacity:0}.VPBackdrop.fade-leave-active[data-v-c79a1216]{transition-duration:.25s}@media (min-width: 1280px){.VPBackdrop[data-v-c79a1216]{display:none}}.NotFound[data-v-f87ff6e4]{padding:64px 24px 96px;text-align:center}@media (min-width: 768px){.NotFound[data-v-f87ff6e4]{padding:96px 32px 168px}}.code[data-v-f87ff6e4]{line-height:64px;font-size:64px;font-weight:600}.title[data-v-f87ff6e4]{padding-top:12px;letter-spacing:2px;line-height:20px;font-size:20px;font-weight:700}.divider[data-v-f87ff6e4]{margin:24px auto 18px;width:64px;height:1px;background-color:var(--vp-c-divider)}.quote[data-v-f87ff6e4]{margin:0 auto;max-width:256px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.action[data-v-f87ff6e4]{padding-top:20px}.link[data-v-f87ff6e4]{display:inline-block;border:1px solid var(--vp-c-brand-1);border-radius:16px;padding:3px 16px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:border-color .25s,color .25s}.link[data-v-f87ff6e4]:hover{border-color:var(--vp-c-brand-2);color:var(--vp-c-brand-2)}.root[data-v-d0ee3533]{position:relative;z-index:1}.nested[data-v-d0ee3533]{padding-left:16px}.outline-link[data-v-d0ee3533]{display:block;line-height:28px;color:var(--vp-c-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .5s;font-weight:400}.outline-link[data-v-d0ee3533]:hover,.outline-link.active[data-v-d0ee3533]{color:var(--vp-c-text-1);transition:color .25s}.outline-link.nested[data-v-d0ee3533]{padding-left:13px}.VPDocAsideOutline[data-v-d330b1bb]{display:none}.VPDocAsideOutline.has-outline[data-v-d330b1bb]{display:block}.content[data-v-d330b1bb]{position:relative;border-left:1px solid var(--vp-c-divider);padding-left:16px;font-size:13px;font-weight:500}.outline-marker[data-v-d330b1bb]{position:absolute;top:32px;left:-1px;z-index:0;opacity:0;width:2px;border-radius:2px;height:18px;background-color:var(--vp-c-brand-1);transition:top .25s cubic-bezier(0,1,.5,1),background-color .5s,opacity .25s}.outline-title[data-v-d330b1bb]{letter-spacing:.4px;line-height:28px;font-size:13px;font-weight:600}.VPDocAside[data-v-3f215769]{display:flex;flex-direction:column;flex-grow:1}.spacer[data-v-3f215769]{flex-grow:1}.VPDocAside[data-v-3f215769] .spacer+.VPDocAsideSponsors,.VPDocAside[data-v-3f215769] .spacer+.VPDocAsideCarbonAds{margin-top:24px}.VPDocAside[data-v-3f215769] .VPDocAsideSponsors+.VPDocAsideCarbonAds{margin-top:16px}.VPLastUpdated[data-v-7e05ebdb]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 640px){.VPLastUpdated[data-v-7e05ebdb]{line-height:32px;font-size:14px;font-weight:500}}.VPDocFooter[data-v-ef5dee53]{margin-top:64px}.edit-info[data-v-ef5dee53]{padding-bottom:18px}@media (min-width: 640px){.edit-info[data-v-ef5dee53]{display:flex;justify-content:space-between;align-items:center;padding-bottom:14px}}.edit-link-button[data-v-ef5dee53]{display:flex;align-items:center;border:0;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.edit-link-button[data-v-ef5dee53]:hover{color:var(--vp-c-brand-2)}.edit-link-icon[data-v-ef5dee53]{margin-right:8px;width:14px;height:14px;fill:currentColor}.prev-next[data-v-ef5dee53]{border-top:1px solid var(--vp-c-divider);padding-top:24px;display:grid;grid-row-gap:8px}@media (min-width: 640px){.prev-next[data-v-ef5dee53]{grid-template-columns:repeat(2,1fr);grid-column-gap:16px}}.pager-link[data-v-ef5dee53]{display:block;border:1px solid var(--vp-c-divider);border-radius:8px;padding:11px 16px 13px;width:100%;height:100%;transition:border-color .25s}.pager-link[data-v-ef5dee53]:hover{border-color:var(--vp-c-brand-1)}.pager-link.next[data-v-ef5dee53]{margin-left:auto;text-align:right}.desc[data-v-ef5dee53]{display:block;line-height:20px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.title[data-v-ef5dee53]{display:block;line-height:20px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.VPDocOutlineDropdown[data-v-eadfb36b]{margin-bottom:48px}.VPDocOutlineDropdown button[data-v-eadfb36b]{display:block;font-size:14px;font-weight:500;line-height:24px;border:1px solid var(--vp-c-border);padding:4px 12px;color:var(--vp-c-text-2);background-color:var(--vp-c-default-soft);border-radius:8px;transition:color .5s}.VPDocOutlineDropdown button[data-v-eadfb36b]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPDocOutlineDropdown button.open[data-v-eadfb36b]{color:var(--vp-c-text-1)}.icon[data-v-eadfb36b]{display:inline-block;vertical-align:middle;width:16px;height:16px;fill:currentColor}[data-v-eadfb36b] .outline-link{font-size:14px;font-weight:400}.open>.icon[data-v-eadfb36b]{transform:rotate(90deg)}.items[data-v-eadfb36b]{margin-top:12px;border-left:1px solid var(--vp-c-divider)}.VPDoc[data-v-6b87e69f]{padding:32px 24px 96px;width:100%}.VPDoc .VPDocOutlineDropdown[data-v-6b87e69f]{display:none}@media (min-width: 960px) and (max-width: 1279px){.VPDoc .VPDocOutlineDropdown[data-v-6b87e69f]{display:block}}@media (min-width: 768px){.VPDoc[data-v-6b87e69f]{padding:48px 32px 128px}}@media (min-width: 960px){.VPDoc[data-v-6b87e69f]{padding:32px 32px 0}.VPDoc:not(.has-sidebar) .container[data-v-6b87e69f]{display:flex;justify-content:center;max-width:992px}.VPDoc:not(.has-sidebar) .content[data-v-6b87e69f]{max-width:752px}}@media (min-width: 1280px){.VPDoc .container[data-v-6b87e69f]{display:flex;justify-content:center}.VPDoc .aside[data-v-6b87e69f]{display:block}}@media (min-width: 1440px){.VPDoc:not(.has-sidebar) .content[data-v-6b87e69f]{max-width:784px}.VPDoc:not(.has-sidebar) .container[data-v-6b87e69f]{max-width:1104px}}.container[data-v-6b87e69f]{margin:0 auto;width:100%}.aside[data-v-6b87e69f]{position:relative;display:none;order:2;flex-grow:1;padding-left:32px;width:100%;max-width:256px}.left-aside[data-v-6b87e69f]{order:1;padding-left:unset;padding-right:32px}.aside-container[data-v-6b87e69f]{position:fixed;top:0;padding-top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 32px);width:224px;height:100vh;overflow-x:hidden;overflow-y:auto;scrollbar-width:none}.aside-container[data-v-6b87e69f]::-webkit-scrollbar{display:none}.aside-curtain[data-v-6b87e69f]{position:fixed;bottom:0;z-index:10;width:224px;height:32px;background:linear-gradient(transparent,var(--vp-c-bg) 70%)}.aside-content[data-v-6b87e69f]{display:flex;flex-direction:column;min-height:calc(100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 32px));padding-bottom:32px}.content[data-v-6b87e69f]{position:relative;margin:0 auto;width:100%}@media (min-width: 960px){.content[data-v-6b87e69f]{padding:0 32px 128px}}@media (min-width: 1280px){.content[data-v-6b87e69f]{order:1;margin:0;min-width:640px}}.content-container[data-v-6b87e69f]{margin:0 auto}.VPDoc.has-aside .content-container[data-v-6b87e69f]{max-width:688px}.external-link-icon-enabled[data-v-6b87e69f] :is(.vp-doc a[href*="://"],.vp-doc a[target=_blank]):after{content:"";color:currentColor}.VPButton[data-v-c1c5efc1]{display:inline-block;border:1px solid transparent;text-align:center;font-weight:600;white-space:nowrap;transition:color .25s,border-color .25s,background-color .25s}.VPButton[data-v-c1c5efc1]:active{transition:color .1s,border-color .1s,background-color .1s}.VPButton.medium[data-v-c1c5efc1]{border-radius:20px;padding:0 20px;line-height:38px;font-size:14px}.VPButton.big[data-v-c1c5efc1]{border-radius:24px;padding:0 24px;line-height:46px;font-size:16px}.VPButton.brand[data-v-c1c5efc1]{border-color:var(--vp-button-brand-border);color:var(--vp-button-brand-text);background-color:var(--vp-button-brand-bg)}.VPButton.brand[data-v-c1c5efc1]:hover{border-color:var(--vp-button-brand-hover-border);color:var(--vp-button-brand-hover-text);background-color:var(--vp-button-brand-hover-bg)}.VPButton.brand[data-v-c1c5efc1]:active{border-color:var(--vp-button-brand-active-border);color:var(--vp-button-brand-active-text);background-color:var(--vp-button-brand-active-bg)}.VPButton.alt[data-v-c1c5efc1]{border-color:var(--vp-button-alt-border);color:var(--vp-button-alt-text);background-color:var(--vp-button-alt-bg)}.VPButton.alt[data-v-c1c5efc1]:hover{border-color:var(--vp-button-alt-hover-border);color:var(--vp-button-alt-hover-text);background-color:var(--vp-button-alt-hover-bg)}.VPButton.alt[data-v-c1c5efc1]:active{border-color:var(--vp-button-alt-active-border);color:var(--vp-button-alt-active-text);background-color:var(--vp-button-alt-active-bg)}.VPButton.sponsor[data-v-c1c5efc1]{border-color:var(--vp-button-sponsor-border);color:var(--vp-button-sponsor-text);background-color:var(--vp-button-sponsor-bg)}.VPButton.sponsor[data-v-c1c5efc1]:hover{border-color:var(--vp-button-sponsor-hover-border);color:var(--vp-button-sponsor-hover-text);background-color:var(--vp-button-sponsor-hover-bg)}.VPButton.sponsor[data-v-c1c5efc1]:active{border-color:var(--vp-button-sponsor-active-border);color:var(--vp-button-sponsor-active-text);background-color:var(--vp-button-sponsor-active-bg)}html:not(.dark) .VPImage.dark[data-v-8426fc1a]{display:none}.dark .VPImage.light[data-v-8426fc1a]{display:none}.VPHero[data-v-da5d1713]{margin-top:calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px}@media (min-width: 640px){.VPHero[data-v-da5d1713]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px}}@media (min-width: 960px){.VPHero[data-v-da5d1713]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px}}.container[data-v-da5d1713]{display:flex;flex-direction:column;margin:0 auto;max-width:1152px}@media (min-width: 960px){.container[data-v-da5d1713]{flex-direction:row}}.main[data-v-da5d1713]{position:relative;z-index:10;order:2;flex-grow:1;flex-shrink:0}.VPHero.has-image .container[data-v-da5d1713]{text-align:center}@media (min-width: 960px){.VPHero.has-image .container[data-v-da5d1713]{text-align:left}}@media (min-width: 960px){.main[data-v-da5d1713]{order:1;width:calc((100% / 3) * 2)}.VPHero.has-image .main[data-v-da5d1713]{max-width:592px}}.name[data-v-da5d1713],.text[data-v-da5d1713]{max-width:392px;letter-spacing:-.4px;line-height:40px;font-size:32px;font-weight:700;white-space:pre-wrap}.VPHero.has-image .name[data-v-da5d1713],.VPHero.has-image .text[data-v-da5d1713]{margin:0 auto}.name[data-v-da5d1713]{color:var(--vp-home-hero-name-color)}.clip[data-v-da5d1713]{background:var(--vp-home-hero-name-background);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}@media (min-width: 640px){.name[data-v-da5d1713],.text[data-v-da5d1713]{max-width:576px;line-height:56px;font-size:48px}}@media (min-width: 960px){.name[data-v-da5d1713],.text[data-v-da5d1713]{line-height:64px;font-size:56px}.VPHero.has-image .name[data-v-da5d1713],.VPHero.has-image .text[data-v-da5d1713]{margin:0}}.tagline[data-v-da5d1713]{padding-top:8px;max-width:392px;line-height:28px;font-size:18px;font-weight:500;white-space:pre-wrap;color:var(--vp-c-text-2)}.VPHero.has-image .tagline[data-v-da5d1713]{margin:0 auto}@media (min-width: 640px){.tagline[data-v-da5d1713]{padding-top:12px;max-width:576px;line-height:32px;font-size:20px}}@media (min-width: 960px){.tagline[data-v-da5d1713]{line-height:36px;font-size:24px}.VPHero.has-image .tagline[data-v-da5d1713]{margin:0}}.actions[data-v-da5d1713]{display:flex;flex-wrap:wrap;margin:-6px;padding-top:24px}.VPHero.has-image .actions[data-v-da5d1713]{justify-content:center}@media (min-width: 640px){.actions[data-v-da5d1713]{padding-top:32px}}@media (min-width: 960px){.VPHero.has-image .actions[data-v-da5d1713]{justify-content:flex-start}}.action[data-v-da5d1713]{flex-shrink:0;padding:6px}.image[data-v-da5d1713]{order:1;margin:-76px -24px -48px}@media (min-width: 640px){.image[data-v-da5d1713]{margin:-108px -24px -48px}}@media (min-width: 960px){.image[data-v-da5d1713]{flex-grow:1;order:2;margin:0;min-height:100%}}.image-container[data-v-da5d1713]{position:relative;margin:0 auto;width:320px;height:320px}@media (min-width: 640px){.image-container[data-v-da5d1713]{width:392px;height:392px}}@media (min-width: 960px){.image-container[data-v-da5d1713]{display:flex;justify-content:center;align-items:center;width:100%;height:100%;transform:translate(-32px,-32px)}}.image-bg[data-v-da5d1713]{position:absolute;top:50%;left:50%;border-radius:50%;width:192px;height:192px;background-image:var(--vp-home-hero-image-background-image);filter:var(--vp-home-hero-image-filter);transform:translate(-50%,-50%)}@media (min-width: 640px){.image-bg[data-v-da5d1713]{width:256px;height:256px}}@media (min-width: 960px){.image-bg[data-v-da5d1713]{width:320px;height:320px}}[data-v-da5d1713] .image-src{position:absolute;top:50%;left:50%;max-width:192px;max-height:192px;transform:translate(-50%,-50%)}@media (min-width: 640px){[data-v-da5d1713] .image-src{max-width:256px;max-height:256px}}@media (min-width: 960px){[data-v-da5d1713] .image-src{max-width:320px;max-height:320px}}.VPFeature[data-v-33204567]{display:block;border:1px solid var(--vp-c-bg-soft);border-radius:12px;height:100%;background-color:var(--vp-c-bg-soft);transition:border-color .25s,background-color .25s}.VPFeature.link[data-v-33204567]:hover{border-color:var(--vp-c-brand-1)}.box[data-v-33204567]{display:flex;flex-direction:column;padding:24px;height:100%}.box[data-v-33204567]>.VPImage{margin-bottom:20px}.icon[data-v-33204567]{display:flex;justify-content:center;align-items:center;margin-bottom:20px;border-radius:6px;background-color:var(--vp-c-default-soft);width:48px;height:48px;font-size:24px;transition:background-color .25s}.title[data-v-33204567]{line-height:24px;font-size:16px;font-weight:600}.details[data-v-33204567]{flex-grow:1;padding-top:8px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.link-text[data-v-33204567]{padding-top:8px}.link-text-value[data-v-33204567]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.link-text-icon[data-v-33204567]{display:inline-block;margin-left:6px;width:14px;height:14px;fill:currentColor}.VPFeatures[data-v-a6181336]{position:relative;padding:0 24px}@media (min-width: 640px){.VPFeatures[data-v-a6181336]{padding:0 48px}}@media (min-width: 960px){.VPFeatures[data-v-a6181336]{padding:0 64px}}.container[data-v-a6181336]{margin:0 auto;max-width:1152px}.items[data-v-a6181336]{display:flex;flex-wrap:wrap;margin:-8px}.item[data-v-a6181336]{padding:8px;width:100%}@media (min-width: 640px){.item.grid-2[data-v-a6181336],.item.grid-4[data-v-a6181336],.item.grid-6[data-v-a6181336]{width:50%}}@media (min-width: 768px){.item.grid-2[data-v-a6181336],.item.grid-4[data-v-a6181336]{width:50%}.item.grid-3[data-v-a6181336],.item.grid-6[data-v-a6181336]{width:calc(100% / 3)}}@media (min-width: 960px){.item.grid-4[data-v-a6181336]{width:25%}}.VPHome[data-v-d82743a8]{padding-bottom:96px}.VPHome[data-v-d82743a8] .VPHomeSponsors{margin-top:112px;margin-bottom:-128px}@media (min-width: 768px){.VPHome[data-v-d82743a8]{padding-bottom:128px}}.VPContent[data-v-669faec9]{flex-grow:1;flex-shrink:0;margin:var(--vp-layout-top-height, 0px) auto 0;width:100%}.VPContent.is-home[data-v-669faec9]{width:100%;max-width:100%}.VPContent.has-sidebar[data-v-669faec9]{margin:0}@media (min-width: 960px){.VPContent[data-v-669faec9]{padding-top:var(--vp-nav-height)}.VPContent.has-sidebar[data-v-669faec9]{margin:var(--vp-layout-top-height, 0px) 0 0;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPContent.has-sidebar[data-v-669faec9]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.VPFooter[data-v-e03eb2e1]{position:relative;z-index:var(--vp-z-index-footer);border-top:1px solid var(--vp-c-gutter);padding:32px 24px;background-color:var(--vp-c-bg)}.VPFooter.has-sidebar[data-v-e03eb2e1]{display:none}@media (min-width: 768px){.VPFooter[data-v-e03eb2e1]{padding:32px}}.container[data-v-e03eb2e1]{margin:0 auto;max-width:var(--vp-layout-max-width);text-align:center}.message[data-v-e03eb2e1],.copyright[data-v-e03eb2e1]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.VPLocalNavOutlineDropdown[data-v-1c15a60a]{padding:12px 20px 11px}.VPLocalNavOutlineDropdown button[data-v-1c15a60a]{display:block;font-size:12px;font-weight:500;line-height:24px;color:var(--vp-c-text-2);transition:color .5s;position:relative}.VPLocalNavOutlineDropdown button[data-v-1c15a60a]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPLocalNavOutlineDropdown button.open[data-v-1c15a60a]{color:var(--vp-c-text-1)}.icon[data-v-1c15a60a]{display:inline-block;vertical-align:middle;margin-left:2px;width:14px;height:14px;fill:currentColor}[data-v-1c15a60a] .outline-link{font-size:14px;padding:2px 0}.open>.icon[data-v-1c15a60a]{transform:rotate(90deg)}.items[data-v-1c15a60a]{position:absolute;top:64px;right:16px;left:16px;display:grid;gap:1px;border:1px solid var(--vp-c-border);border-radius:8px;background-color:var(--vp-c-gutter);max-height:calc(var(--vp-vh, 100vh) - 86px);overflow:hidden auto;box-shadow:var(--vp-shadow-3)}.header[data-v-1c15a60a]{background-color:var(--vp-c-bg-soft)}.top-link[data-v-1c15a60a]{display:block;padding:0 16px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.outline[data-v-1c15a60a]{padding:8px 0;background-color:var(--vp-c-bg-soft)}.flyout-enter-active[data-v-1c15a60a]{transition:all .2s ease-out}.flyout-leave-active[data-v-1c15a60a]{transition:all .15s ease-in}.flyout-enter-from[data-v-1c15a60a],.flyout-leave-to[data-v-1c15a60a]{opacity:0;transform:translateY(-16px)}.VPLocalNav[data-v-79c8c1df]{position:sticky;top:0;left:0;z-index:var(--vp-z-index-local-nav);display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--vp-c-gutter);border-bottom:1px solid var(--vp-c-gutter);padding-top:var(--vp-layout-top-height, 0px);width:100%;background-color:var(--vp-local-nav-bg-color)}.VPLocalNav.fixed[data-v-79c8c1df]{position:fixed}.VPLocalNav.reached-top[data-v-79c8c1df]{border-top-color:transparent}@media (min-width: 960px){.VPLocalNav[data-v-79c8c1df]{display:none}}.menu[data-v-79c8c1df]{display:flex;align-items:center;padding:12px 24px 11px;line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.menu[data-v-79c8c1df]:hover{color:var(--vp-c-text-1);transition:color .25s}@media (min-width: 768px){.menu[data-v-79c8c1df]{padding:0 32px}}.menu-icon[data-v-79c8c1df]{margin-right:8px;width:16px;height:16px;fill:currentColor}.VPOutlineDropdown[data-v-79c8c1df]{padding:12px 24px 11px}@media (min-width: 768px){.VPOutlineDropdown[data-v-79c8c1df]{padding:12px 32px 11px}}.VPSwitch[data-v-b1685198]{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--vp-input-border-color);background-color:var(--vp-input-switch-bg-color);transition:border-color .25s!important}.VPSwitch[data-v-b1685198]:hover{border-color:var(--vp-c-brand-1)}.check[data-v-b1685198]{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;background-color:var(--vp-c-neutral-inverse);box-shadow:var(--vp-shadow-1);transition:transform .25s!important}.icon[data-v-b1685198]{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}.icon[data-v-b1685198] svg{position:absolute;top:3px;left:3px;width:12px;height:12px;fill:var(--vp-c-text-2)}.dark .icon[data-v-b1685198] svg{fill:var(--vp-c-text-1);transition:opacity .25s!important}.sun[data-v-ce54a7d1]{opacity:1}.moon[data-v-ce54a7d1],.dark .sun[data-v-ce54a7d1]{opacity:0}.dark .moon[data-v-ce54a7d1]{opacity:1}.dark .VPSwitchAppearance[data-v-ce54a7d1] .check{transform:translate(18px)}.VPNavBarAppearance[data-v-e6aabb21]{display:none}@media (min-width: 1280px){.VPNavBarAppearance[data-v-e6aabb21]{display:flex;align-items:center}}.VPMenuGroup+.VPMenuLink[data-v-43f1e123]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.link[data-v-43f1e123]{display:block;border-radius:6px;padding:0 12px;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);white-space:nowrap;transition:background-color .25s,color .25s}.link[data-v-43f1e123]:hover{color:var(--vp-c-brand-1);background-color:var(--vp-c-default-soft)}.link.active[data-v-43f1e123]{color:var(--vp-c-brand-1)}.VPMenuGroup[data-v-69e747b5]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.VPMenuGroup[data-v-69e747b5]:first-child{margin-top:0;border-top:0;padding-top:0}.VPMenuGroup+.VPMenuGroup[data-v-69e747b5]{margin-top:12px;border-top:1px solid var(--vp-c-divider)}.title[data-v-69e747b5]{padding:0 12px;line-height:32px;font-size:14px;font-weight:600;color:var(--vp-c-text-2);white-space:nowrap;transition:color .25s}.VPMenu[data-v-e7ea1737]{border-radius:12px;padding:12px;min-width:128px;border:1px solid var(--vp-c-divider);background-color:var(--vp-c-bg-elv);box-shadow:var(--vp-shadow-3);transition:background-color .5s;max-height:calc(100vh - var(--vp-nav-height));overflow-y:auto}.VPMenu[data-v-e7ea1737] .group{margin:0 -12px;padding:0 12px 12px}.VPMenu[data-v-e7ea1737] .group+.group{border-top:1px solid var(--vp-c-divider);padding:11px 12px 12px}.VPMenu[data-v-e7ea1737] .group:last-child{padding-bottom:0}.VPMenu[data-v-e7ea1737] .group+.item{border-top:1px solid var(--vp-c-divider);padding:11px 16px 0}.VPMenu[data-v-e7ea1737] .item{padding:0 16px;white-space:nowrap}.VPMenu[data-v-e7ea1737] .label{flex-grow:1;line-height:28px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.VPMenu[data-v-e7ea1737] .action{padding-left:24px}.VPFlyout[data-v-9c007e85]{position:relative}.VPFlyout[data-v-9c007e85]:hover{color:var(--vp-c-brand-1);transition:color .25s}.VPFlyout:hover .text[data-v-9c007e85]{color:var(--vp-c-text-2)}.VPFlyout:hover .icon[data-v-9c007e85]{fill:var(--vp-c-text-2)}.VPFlyout.active .text[data-v-9c007e85]{color:var(--vp-c-brand-1)}.VPFlyout.active:hover .text[data-v-9c007e85]{color:var(--vp-c-brand-2)}.VPFlyout:hover .menu[data-v-9c007e85],.button[aria-expanded=true]+.menu[data-v-9c007e85]{opacity:1;visibility:visible;transform:translateY(0)}.button[aria-expanded=false]+.menu[data-v-9c007e85]{opacity:0;visibility:hidden;transform:translateY(0)}.button[data-v-9c007e85]{display:flex;align-items:center;padding:0 12px;height:var(--vp-nav-height);color:var(--vp-c-text-1);transition:color .5s}.text[data-v-9c007e85]{display:flex;align-items:center;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.option-icon[data-v-9c007e85]{margin-right:0;width:16px;height:16px;fill:currentColor}.text-icon[data-v-9c007e85]{margin-left:4px;width:14px;height:14px;fill:currentColor}.icon[data-v-9c007e85]{width:20px;height:20px;fill:currentColor;transition:fill .25s}.menu[data-v-9c007e85]{position:absolute;top:calc(var(--vp-nav-height) / 2 + 20px);right:0;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s,transform .25s}.VPSocialLink[data-v-f80f8133]{display:flex;justify-content:center;align-items:center;width:36px;height:36px;color:var(--vp-c-text-2);transition:color .5s}.VPSocialLink[data-v-f80f8133]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPSocialLink[data-v-f80f8133]>svg{width:20px;height:20px;fill:currentColor}.VPSocialLinks[data-v-7bc22406]{display:flex;justify-content:center}.VPNavBarExtra[data-v-40855f84]{display:none;margin-right:-12px}@media (min-width: 768px){.VPNavBarExtra[data-v-40855f84]{display:block}}@media (min-width: 1280px){.VPNavBarExtra[data-v-40855f84]{display:none}}.trans-title[data-v-40855f84]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.item.appearance[data-v-40855f84],.item.social-links[data-v-40855f84]{display:flex;align-items:center;padding:0 12px}.item.appearance[data-v-40855f84]{min-width:176px}.appearance-action[data-v-40855f84]{margin-right:-2px}.social-links-list[data-v-40855f84]{margin:-4px -8px}.VPNavBarHamburger[data-v-e5dd9c1c]{display:flex;justify-content:center;align-items:center;width:48px;height:var(--vp-nav-height)}@media (min-width: 768px){.VPNavBarHamburger[data-v-e5dd9c1c]{display:none}}.container[data-v-e5dd9c1c]{position:relative;width:16px;height:14px;overflow:hidden}.VPNavBarHamburger:hover .top[data-v-e5dd9c1c]{top:0;left:0;transform:translate(4px)}.VPNavBarHamburger:hover .middle[data-v-e5dd9c1c]{top:6px;left:0;transform:translate(0)}.VPNavBarHamburger:hover .bottom[data-v-e5dd9c1c]{top:12px;left:0;transform:translate(8px)}.VPNavBarHamburger.active .top[data-v-e5dd9c1c]{top:6px;transform:translate(0) rotate(225deg)}.VPNavBarHamburger.active .middle[data-v-e5dd9c1c]{top:6px;transform:translate(16px)}.VPNavBarHamburger.active .bottom[data-v-e5dd9c1c]{top:6px;transform:translate(0) rotate(135deg)}.VPNavBarHamburger.active:hover .top[data-v-e5dd9c1c],.VPNavBarHamburger.active:hover .middle[data-v-e5dd9c1c],.VPNavBarHamburger.active:hover .bottom[data-v-e5dd9c1c]{background-color:var(--vp-c-text-2);transition:top .25s,background-color .25s,transform .25s}.top[data-v-e5dd9c1c],.middle[data-v-e5dd9c1c],.bottom[data-v-e5dd9c1c]{position:absolute;width:16px;height:2px;background-color:var(--vp-c-text-1);transition:top .25s,background-color .5s,transform .25s}.top[data-v-e5dd9c1c]{top:0;left:0;transform:translate(0)}.middle[data-v-e5dd9c1c]{top:6px;left:0;transform:translate(8px)}.bottom[data-v-e5dd9c1c]{top:12px;left:0;transform:translate(4px)}.VPNavBarMenuLink[data-v-42ef59de]{display:flex;align-items:center;padding:0 12px;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.VPNavBarMenuLink.active[data-v-42ef59de],.VPNavBarMenuLink[data-v-42ef59de]:hover{color:var(--vp-c-brand-1)}.VPNavBarMenu[data-v-7f418b0f]{display:none}@media (min-width: 768px){.VPNavBarMenu[data-v-7f418b0f]{display:flex}}/*! @docsearch/css 3.5.2 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;position:relative;padding:0 0 2px;border:0;top:-1px;width:20px}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:rgba(0,0,0,.2);transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:rgba(0,0,0,.2);transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border-radius:2px;box-shadow:var(--docsearch-key-shadow);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;color:var(--docsearch-muted-color);border:0;width:20px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}[class*=DocSearch]{--docsearch-primary-color: var(--vp-c-brand-1);--docsearch-highlight-color: var(--docsearch-primary-color);--docsearch-text-color: var(--vp-c-text-1);--docsearch-muted-color: var(--vp-c-text-2);--docsearch-searchbox-shadow: none;--docsearch-searchbox-background: transparent;--docsearch-searchbox-focus-background: transparent;--docsearch-key-gradient: transparent;--docsearch-key-shadow: none;--docsearch-modal-background: var(--vp-c-bg-soft);--docsearch-footer-background: var(--vp-c-bg)}.dark [class*=DocSearch]{--docsearch-modal-shadow: none;--docsearch-footer-shadow: none;--docsearch-logo-color: var(--vp-c-text-2);--docsearch-hit-background: var(--vp-c-default-soft);--docsearch-hit-color: var(--vp-c-text-2);--docsearch-hit-shadow: none}.DocSearch-Button{display:flex;justify-content:center;align-items:center;margin:0;padding:0;width:48px;height:55px;background:transparent;transition:border-color .25s}.DocSearch-Button:hover{background:transparent}.DocSearch-Button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.DocSearch-Button:focus:not(:focus-visible){outline:none!important}@media (min-width: 768px){.DocSearch-Button{justify-content:flex-start;border:1px solid transparent;border-radius:8px;padding:0 10px 0 12px;width:100%;height:40px;background-color:var(--vp-c-bg-alt)}.DocSearch-Button:hover{border-color:var(--vp-c-brand-1);background:var(--vp-c-bg-alt)}}.DocSearch-Button .DocSearch-Button-Container{display:flex;align-items:center}.DocSearch-Button .DocSearch-Search-Icon{position:relative;width:16px;height:16px;color:var(--vp-c-text-1);fill:currentColor;transition:color .5s}.DocSearch-Button:hover .DocSearch-Search-Icon{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Search-Icon{top:1px;margin-right:8px;width:14px;height:14px;color:var(--vp-c-text-2)}}.DocSearch-Button .DocSearch-Button-Placeholder{display:none;margin-top:2px;padding:0 16px 0 0;font-size:13px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.DocSearch-Button:hover .DocSearch-Button-Placeholder{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Placeholder{display:inline-block}}.DocSearch-Button .DocSearch-Button-Keys{direction:ltr;display:none;min-width:auto}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Keys{display:flex;align-items:center}}.DocSearch-Button .DocSearch-Button-Key{display:block;margin:2px 0 0;border:1px solid var(--vp-c-divider);border-right:none;border-radius:4px 0 0 4px;padding-left:6px;min-width:0;width:auto;height:22px;line-height:22px;font-family:var(--vp-font-family-base);font-size:12px;font-weight:500;transition:color .5s,border-color .5s}.DocSearch-Button .DocSearch-Button-Key+.DocSearch-Button-Key{border-right:1px solid var(--vp-c-divider);border-left:none;border-radius:0 4px 4px 0;padding-left:2px;padding-right:6px}.DocSearch-Button .DocSearch-Button-Key:first-child{font-size:0!important}.DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"Ctrl";font-size:12px;letter-spacing:normal;color:var(--docsearch-muted-color)}.mac .DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"⌘"}.DocSearch-Button .DocSearch-Button-Key:first-child>*{display:none}.VPNavBarSearch{display:flex;align-items:center}@media (min-width: 768px){.VPNavBarSearch{flex-grow:1;padding-left:24px}}@media (min-width: 960px){.VPNavBarSearch{padding-left:32px}}.dark .DocSearch-Footer{border-top:1px solid var(--vp-c-divider)}.DocSearch-Form{border:1px solid var(--vp-c-brand-1);background-color:var(--vp-c-white)}.dark .DocSearch-Form{background-color:var(--vp-c-default-soft)}.DocSearch-Screen-Icon>svg{margin:auto}.VPNavBarSocialLinks[data-v-0394ad82]{display:none}@media (min-width: 1280px){.VPNavBarSocialLinks[data-v-0394ad82]{display:flex;align-items:center}}.title[data-v-86d1bed8]{display:flex;align-items:center;border-bottom:1px solid transparent;width:100%;height:var(--vp-nav-height);font-size:16px;font-weight:600;color:var(--vp-c-text-1);transition:opacity .25s}@media (min-width: 960px){.title[data-v-86d1bed8]{flex-shrink:0}.VPNavBarTitle.has-sidebar .title[data-v-86d1bed8]{border-bottom-color:var(--vp-c-divider)}}[data-v-86d1bed8] .logo{margin-right:8px;height:var(--vp-nav-logo-height)}.VPNavBarTranslations[data-v-74abcbb9]{display:none}@media (min-width: 1280px){.VPNavBarTranslations[data-v-74abcbb9]{display:flex;align-items:center}}.title[data-v-74abcbb9]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.VPNavBar[data-v-a0fd61f4]{position:relative;border-bottom:1px solid transparent;padding:0 8px 0 24px;height:var(--vp-nav-height);pointer-events:none;white-space:nowrap}@media (min-width: 768px){.VPNavBar[data-v-a0fd61f4]{padding:0 32px}}@media (min-width: 960px){.VPNavBar.has-sidebar[data-v-a0fd61f4]{padding:0}.VPNavBar[data-v-a0fd61f4]:not(.has-sidebar):not(.top){border-bottom-color:var(--vp-c-gutter);background-color:var(--vp-nav-bg-color)}}.container[data-v-a0fd61f4]{display:flex;justify-content:space-between;margin:0 auto;max-width:calc(var(--vp-layout-max-width) - 64px);height:var(--vp-nav-height);pointer-events:none}.container>.title[data-v-a0fd61f4],.container>.content[data-v-a0fd61f4]{pointer-events:none}.container[data-v-a0fd61f4] *{pointer-events:auto}@media (min-width: 960px){.VPNavBar.has-sidebar .container[data-v-a0fd61f4]{max-width:100%}}.title[data-v-a0fd61f4]{flex-shrink:0;height:calc(var(--vp-nav-height) - 1px);transition:background-color .5s}@media (min-width: 960px){.VPNavBar.has-sidebar .title[data-v-a0fd61f4]{position:absolute;top:0;left:0;z-index:2;padding:0 32px;width:var(--vp-sidebar-width);height:var(--vp-nav-height);background-color:transparent}}@media (min-width: 1440px){.VPNavBar.has-sidebar .title[data-v-a0fd61f4]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}.content[data-v-a0fd61f4]{flex-grow:1}@media (min-width: 960px){.VPNavBar.has-sidebar .content[data-v-a0fd61f4]{position:relative;z-index:1;padding-right:32px;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .content[data-v-a0fd61f4]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.content-body[data-v-a0fd61f4]{display:flex;justify-content:flex-end;align-items:center;height:calc(var(--vp-nav-height) - 1px);transition:background-color .5s}@media (min-width: 960px){.VPNavBar:not(.top) .content-body[data-v-a0fd61f4]{position:relative;background-color:var(--vp-nav-bg-color)}}@media (max-width: 767px){.content-body[data-v-a0fd61f4]{column-gap:.5rem}}.menu+.translations[data-v-a0fd61f4]:before,.menu+.appearance[data-v-a0fd61f4]:before,.menu+.social-links[data-v-a0fd61f4]:before,.translations+.appearance[data-v-a0fd61f4]:before,.appearance+.social-links[data-v-a0fd61f4]:before{margin-right:8px;margin-left:8px;width:1px;height:24px;background-color:var(--vp-c-divider);content:""}.menu+.appearance[data-v-a0fd61f4]:before,.translations+.appearance[data-v-a0fd61f4]:before{margin-right:16px}.appearance+.social-links[data-v-a0fd61f4]:before{margin-left:16px}.social-links[data-v-a0fd61f4]{margin-right:-8px}@media (min-width: 960px){.VPNavBar.has-sidebar .curtain[data-v-a0fd61f4]{position:absolute;right:0;bottom:-31px;width:calc(100% - var(--vp-sidebar-width));height:32px}.VPNavBar.has-sidebar .curtain[data-v-a0fd61f4]:before{display:block;width:100%;height:32px;background:linear-gradient(var(--vp-c-bg),transparent 70%);content:""}}@media (min-width: 1440px){.VPNavBar.has-sidebar .curtain[data-v-a0fd61f4]{width:calc(100% - ((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)))}}.VPNavScreenAppearance[data-v-add8f686]{display:flex;justify-content:space-between;align-items:center;border-radius:8px;padding:12px 14px 12px 16px;background-color:var(--vp-c-bg-soft)}.text[data-v-add8f686]{line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.VPNavScreenMenuLink[data-v-05f27b2a]{display:block;border-bottom:1px solid var(--vp-c-divider);padding:12px 0 11px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:border-color .25s,color .25s}.VPNavScreenMenuLink[data-v-05f27b2a]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupLink[data-v-19976ae1]{display:block;margin-left:12px;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-1);transition:color .25s}.VPNavScreenMenuGroupLink[data-v-19976ae1]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupSection[data-v-8133b170]{display:block}.title[data-v-8133b170]{line-height:32px;font-size:13px;font-weight:700;color:var(--vp-c-text-2);transition:color .25s}.VPNavScreenMenuGroup[data-v-1ecb84e7]{border-bottom:1px solid var(--vp-c-divider);height:48px;overflow:hidden;transition:border-color .5s}.VPNavScreenMenuGroup .items[data-v-1ecb84e7]{visibility:hidden}.VPNavScreenMenuGroup.open .items[data-v-1ecb84e7]{visibility:visible}.VPNavScreenMenuGroup.open[data-v-1ecb84e7]{padding-bottom:10px;height:auto}.VPNavScreenMenuGroup.open .button[data-v-1ecb84e7]{padding-bottom:6px;color:var(--vp-c-brand-1)}.VPNavScreenMenuGroup.open .button-icon[data-v-1ecb84e7]{transform:rotate(45deg)}.button[data-v-1ecb84e7]{display:flex;justify-content:space-between;align-items:center;padding:12px 4px 11px 0;width:100%;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.button[data-v-1ecb84e7]:hover{color:var(--vp-c-brand-1)}.button-icon[data-v-1ecb84e7]{width:14px;height:14px;fill:var(--vp-c-text-2);transition:fill .5s,transform .25s}.group[data-v-1ecb84e7]:first-child{padding-top:0}.group+.group[data-v-1ecb84e7],.group+.item[data-v-1ecb84e7]{padding-top:4px}.VPNavScreenTranslations[data-v-d72aa483]{height:24px;overflow:hidden}.VPNavScreenTranslations.open[data-v-d72aa483]{height:auto}.title[data-v-d72aa483]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-text-1)}.icon[data-v-d72aa483]{width:16px;height:16px;fill:currentColor}.icon.lang[data-v-d72aa483]{margin-right:8px}.icon.chevron[data-v-d72aa483]{margin-left:4px}.list[data-v-d72aa483]{padding:4px 0 0 24px}.link[data-v-d72aa483]{line-height:32px;font-size:13px;color:var(--vp-c-text-1)}.VPNavScreen[data-v-cc5739dd]{position:fixed;top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 1px);right:0;bottom:0;left:0;padding:0 32px;width:100%;background-color:var(--vp-nav-screen-bg-color);overflow-y:auto;transition:background-color .5s;pointer-events:auto}.VPNavScreen.fade-enter-active[data-v-cc5739dd],.VPNavScreen.fade-leave-active[data-v-cc5739dd]{transition:opacity .25s}.VPNavScreen.fade-enter-active .container[data-v-cc5739dd],.VPNavScreen.fade-leave-active .container[data-v-cc5739dd]{transition:transform .25s ease}.VPNavScreen.fade-enter-from[data-v-cc5739dd],.VPNavScreen.fade-leave-to[data-v-cc5739dd]{opacity:0}.VPNavScreen.fade-enter-from .container[data-v-cc5739dd],.VPNavScreen.fade-leave-to .container[data-v-cc5739dd]{transform:translateY(-8px)}@media (min-width: 768px){.VPNavScreen[data-v-cc5739dd]{display:none}}.container[data-v-cc5739dd]{margin:0 auto;padding:24px 0 96px;max-width:288px}.menu+.translations[data-v-cc5739dd],.menu+.appearance[data-v-cc5739dd],.translations+.appearance[data-v-cc5739dd]{margin-top:24px}.menu+.social-links[data-v-cc5739dd]{margin-top:16px}.appearance+.social-links[data-v-cc5739dd]{margin-top:16px}.VPNav[data-v-ae24b3ad]{position:relative;top:var(--vp-layout-top-height, 0px);left:0;z-index:var(--vp-z-index-nav);width:100%;pointer-events:none;transition:background-color .5s}@media (min-width: 960px){.VPNav[data-v-ae24b3ad]{position:fixed}}.VPSidebarItem.level-0[data-v-e31bd47b]{padding-bottom:24px}.VPSidebarItem.collapsed.level-0[data-v-e31bd47b]{padding-bottom:10px}.item[data-v-e31bd47b]{position:relative;display:flex;width:100%}.VPSidebarItem.collapsible>.item[data-v-e31bd47b]{cursor:pointer}.indicator[data-v-e31bd47b]{position:absolute;top:6px;bottom:6px;left:-17px;width:2px;border-radius:2px;transition:background-color .25s}.VPSidebarItem.level-2.is-active>.item>.indicator[data-v-e31bd47b],.VPSidebarItem.level-3.is-active>.item>.indicator[data-v-e31bd47b],.VPSidebarItem.level-4.is-active>.item>.indicator[data-v-e31bd47b],.VPSidebarItem.level-5.is-active>.item>.indicator[data-v-e31bd47b]{background-color:var(--vp-c-brand-1)}.link[data-v-e31bd47b]{display:flex;align-items:center;flex-grow:1}.text[data-v-e31bd47b]{flex-grow:1;padding:4px 0;line-height:24px;font-size:14px;transition:color .25s}.VPSidebarItem.level-0 .text[data-v-e31bd47b]{font-weight:700;color:var(--vp-c-text-1)}.VPSidebarItem.level-1 .text[data-v-e31bd47b],.VPSidebarItem.level-2 .text[data-v-e31bd47b],.VPSidebarItem.level-3 .text[data-v-e31bd47b],.VPSidebarItem.level-4 .text[data-v-e31bd47b],.VPSidebarItem.level-5 .text[data-v-e31bd47b]{font-weight:500;color:var(--vp-c-text-2)}.VPSidebarItem.level-0.is-link>.item>.link:hover .text[data-v-e31bd47b],.VPSidebarItem.level-1.is-link>.item>.link:hover .text[data-v-e31bd47b],.VPSidebarItem.level-2.is-link>.item>.link:hover .text[data-v-e31bd47b],.VPSidebarItem.level-3.is-link>.item>.link:hover .text[data-v-e31bd47b],.VPSidebarItem.level-4.is-link>.item>.link:hover .text[data-v-e31bd47b],.VPSidebarItem.level-5.is-link>.item>.link:hover .text[data-v-e31bd47b]{color:var(--vp-c-brand-1)}.VPSidebarItem.level-0.has-active>.item>.text[data-v-e31bd47b],.VPSidebarItem.level-1.has-active>.item>.text[data-v-e31bd47b],.VPSidebarItem.level-2.has-active>.item>.text[data-v-e31bd47b],.VPSidebarItem.level-3.has-active>.item>.text[data-v-e31bd47b],.VPSidebarItem.level-4.has-active>.item>.text[data-v-e31bd47b],.VPSidebarItem.level-5.has-active>.item>.text[data-v-e31bd47b],.VPSidebarItem.level-0.has-active>.item>.link>.text[data-v-e31bd47b],.VPSidebarItem.level-1.has-active>.item>.link>.text[data-v-e31bd47b],.VPSidebarItem.level-2.has-active>.item>.link>.text[data-v-e31bd47b],.VPSidebarItem.level-3.has-active>.item>.link>.text[data-v-e31bd47b],.VPSidebarItem.level-4.has-active>.item>.link>.text[data-v-e31bd47b],.VPSidebarItem.level-5.has-active>.item>.link>.text[data-v-e31bd47b]{color:var(--vp-c-text-1)}.VPSidebarItem.level-0.is-active>.item .link>.text[data-v-e31bd47b],.VPSidebarItem.level-1.is-active>.item .link>.text[data-v-e31bd47b],.VPSidebarItem.level-2.is-active>.item .link>.text[data-v-e31bd47b],.VPSidebarItem.level-3.is-active>.item .link>.text[data-v-e31bd47b],.VPSidebarItem.level-4.is-active>.item .link>.text[data-v-e31bd47b],.VPSidebarItem.level-5.is-active>.item .link>.text[data-v-e31bd47b]{color:var(--vp-c-brand-1)}.caret[data-v-e31bd47b]{display:flex;justify-content:center;align-items:center;margin-right:-7px;width:32px;height:32px;color:var(--vp-c-text-3);cursor:pointer;transition:color .25s;flex-shrink:0}.item:hover .caret[data-v-e31bd47b]{color:var(--vp-c-text-2)}.item:hover .caret[data-v-e31bd47b]:hover{color:var(--vp-c-text-1)}.caret-icon[data-v-e31bd47b]{width:18px;height:18px;fill:currentColor;transform:rotate(90deg);transition:transform .25s}.VPSidebarItem.collapsed .caret-icon[data-v-e31bd47b]{transform:rotate(0)}.VPSidebarItem.level-1 .items[data-v-e31bd47b],.VPSidebarItem.level-2 .items[data-v-e31bd47b],.VPSidebarItem.level-3 .items[data-v-e31bd47b],.VPSidebarItem.level-4 .items[data-v-e31bd47b],.VPSidebarItem.level-5 .items[data-v-e31bd47b]{border-left:1px solid var(--vp-c-divider);padding-left:16px}.VPSidebarItem.collapsed .items[data-v-e31bd47b]{display:none}.VPSidebar[data-v-b00e2fdd]{position:fixed;top:var(--vp-layout-top-height, 0px);bottom:0;left:0;z-index:var(--vp-z-index-sidebar);padding:32px 32px 96px;width:calc(100vw - 64px);max-width:320px;background-color:var(--vp-sidebar-bg-color);opacity:0;box-shadow:var(--vp-c-shadow-3);overflow-x:hidden;overflow-y:auto;transform:translate(-100%);transition:opacity .5s,transform .25s ease;overscroll-behavior:contain}.VPSidebar.open[data-v-b00e2fdd]{opacity:1;visibility:visible;transform:translate(0);transition:opacity .25s,transform .5s cubic-bezier(.19,1,.22,1)}.dark .VPSidebar[data-v-b00e2fdd]{box-shadow:var(--vp-shadow-1)}@media (min-width: 960px){.VPSidebar[data-v-b00e2fdd]{z-index:1;padding-top:var(--vp-nav-height);padding-bottom:128px;width:var(--vp-sidebar-width);max-width:100%;background-color:var(--vp-sidebar-bg-color);opacity:1;visibility:visible;box-shadow:none;transform:translate(0)}}@media (min-width: 1440px){.VPSidebar[data-v-b00e2fdd]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}@media (min-width: 960px){.curtain[data-v-b00e2fdd]{position:sticky;top:-64px;left:0;z-index:1;margin-top:calc(var(--vp-nav-height) * -1);margin-right:-32px;margin-left:-32px;height:var(--vp-nav-height);background-color:var(--vp-sidebar-bg-color)}}.nav[data-v-b00e2fdd]{outline:0}.group+.group[data-v-b00e2fdd]{border-top:1px solid var(--vp-c-divider);padding-top:10px}@media (min-width: 960px){.group[data-v-b00e2fdd]{padding-top:10px;width:calc(var(--vp-sidebar-width) - 64px)}}.VPSkipLink[data-v-0f60ec36]{top:8px;left:8px;padding:8px 16px;z-index:999;border-radius:8px;font-size:12px;font-weight:700;text-decoration:none;color:var(--vp-c-brand-1);box-shadow:var(--vp-shadow-3);background-color:var(--vp-c-bg)}.VPSkipLink[data-v-0f60ec36]:focus{height:auto;width:auto;clip:auto;clip-path:none}@media (min-width: 1280px){.VPSkipLink[data-v-0f60ec36]{top:14px;left:16px}}.Layout[data-v-5a346dfe]{display:flex;flex-direction:column;min-height:100vh}.VPHomeSponsors[data-v-96bd69d5]{border-top:1px solid var(--vp-c-gutter);padding:88px 24px 96px;background-color:var(--vp-c-bg)}.container[data-v-96bd69d5]{margin:0 auto;max-width:1152px}.love[data-v-96bd69d5]{margin:0 auto;width:28px;height:28px;color:var(--vp-c-text-3)}.icon[data-v-96bd69d5]{width:28px;height:28px;fill:currentColor}.message[data-v-96bd69d5]{margin:0 auto;padding-top:10px;max-width:320px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.sponsors[data-v-96bd69d5]{padding-top:32px}.action[data-v-96bd69d5]{padding-top:40px;text-align:center}.VPTeamPage[data-v-10b00018]{padding-bottom:96px}@media (min-width: 768px){.VPTeamPage[data-v-10b00018]{padding-bottom:128px}}.VPTeamPageSection+.VPTeamPageSection[data-v-10b00018-s],.VPTeamMembers+.VPTeamPageSection[data-v-10b00018-s]{margin-top:64px}.VPTeamMembers+.VPTeamMembers[data-v-10b00018-s]{margin-top:24px}@media (min-width: 768px){.VPTeamPageTitle+.VPTeamPageSection[data-v-10b00018-s]{margin-top:16px}.VPTeamPageSection+.VPTeamPageSection[data-v-10b00018-s],.VPTeamMembers+.VPTeamPageSection[data-v-10b00018-s]{margin-top:96px}}.VPTeamMembers[data-v-10b00018-s]{padding:0 24px}@media (min-width: 768px){.VPTeamMembers[data-v-10b00018-s]{padding:0 48px}}@media (min-width: 960px){.VPTeamMembers[data-v-10b00018-s]{padding:0 64px}}.VPTeamPageTitle[data-v-bf2cbdac]{padding:48px 32px;text-align:center}@media (min-width: 768px){.VPTeamPageTitle[data-v-bf2cbdac]{padding:64px 48px 48px}}@media (min-width: 960px){.VPTeamPageTitle[data-v-bf2cbdac]{padding:80px 64px 48px}}.title[data-v-bf2cbdac]{letter-spacing:0;line-height:44px;font-size:36px;font-weight:500}@media (min-width: 768px){.title[data-v-bf2cbdac]{letter-spacing:-.5px;line-height:56px;font-size:48px}}.lead[data-v-bf2cbdac]{margin:0 auto;max-width:512px;padding-top:12px;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 768px){.lead[data-v-bf2cbdac]{max-width:592px;letter-spacing:.15px;line-height:28px;font-size:20px}}.VPTeamPageSection[data-v-b1a88750]{padding:0 32px}@media (min-width: 768px){.VPTeamPageSection[data-v-b1a88750]{padding:0 48px}}@media (min-width: 960px){.VPTeamPageSection[data-v-b1a88750]{padding:0 64px}}.title[data-v-b1a88750]{position:relative;margin:0 auto;max-width:1152px;text-align:center;color:var(--vp-c-text-2)}.title-line[data-v-b1a88750]{position:absolute;top:16px;left:0;width:100%;height:1px;background-color:var(--vp-c-divider)}.title-text[data-v-b1a88750]{position:relative;display:inline-block;padding:0 24px;letter-spacing:0;line-height:32px;font-size:20px;font-weight:500;background-color:var(--vp-c-bg)}.lead[data-v-b1a88750]{margin:0 auto;max-width:480px;padding-top:12px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.members[data-v-b1a88750]{padding-top:40px}.VPTeamMembersItem[data-v-28528e42]{display:flex;flex-direction:column;gap:2px;border-radius:12px;width:100%;height:100%;overflow:hidden}.VPTeamMembersItem.small .profile[data-v-28528e42]{padding:32px}.VPTeamMembersItem.small .data[data-v-28528e42]{padding-top:20px}.VPTeamMembersItem.small .avatar[data-v-28528e42]{width:64px;height:64px}.VPTeamMembersItem.small .name[data-v-28528e42]{line-height:24px;font-size:16px}.VPTeamMembersItem.small .affiliation[data-v-28528e42]{padding-top:4px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .desc[data-v-28528e42]{padding-top:12px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .links[data-v-28528e42]{margin:0 -16px -20px;padding:10px 0 0}.VPTeamMembersItem.medium .profile[data-v-28528e42]{padding:48px 32px}.VPTeamMembersItem.medium .data[data-v-28528e42]{padding-top:24px;text-align:center}.VPTeamMembersItem.medium .avatar[data-v-28528e42]{width:96px;height:96px}.VPTeamMembersItem.medium .name[data-v-28528e42]{letter-spacing:.15px;line-height:28px;font-size:20px}.VPTeamMembersItem.medium .affiliation[data-v-28528e42]{padding-top:4px;font-size:16px}.VPTeamMembersItem.medium .desc[data-v-28528e42]{padding-top:16px;max-width:288px;font-size:16px}.VPTeamMembersItem.medium .links[data-v-28528e42]{margin:0 -16px -12px;padding:16px 12px 0}.profile[data-v-28528e42]{flex-grow:1;background-color:var(--vp-c-bg-soft)}.data[data-v-28528e42]{text-align:center}.avatar[data-v-28528e42]{position:relative;flex-shrink:0;margin:0 auto;border-radius:50%;box-shadow:var(--vp-shadow-3)}.avatar-img[data-v-28528e42]{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;object-fit:cover}.name[data-v-28528e42]{margin:0;font-weight:600}.affiliation[data-v-28528e42]{margin:0;font-weight:500;color:var(--vp-c-text-2)}.org.link[data-v-28528e42]{color:var(--vp-c-text-2);transition:color .25s}.org.link[data-v-28528e42]:hover{color:var(--vp-c-brand-1)}.desc[data-v-28528e42]{margin:0 auto}.desc[data-v-28528e42] a{font-weight:500;color:var(--vp-c-brand-1);text-decoration-style:dotted;transition:color .25s}.links[data-v-28528e42]{display:flex;justify-content:center;height:56px}.sp-link[data-v-28528e42]{display:flex;justify-content:center;align-items:center;text-align:center;padding:16px;font-size:14px;font-weight:500;color:var(--vp-c-sponsor);background-color:var(--vp-c-bg-soft);transition:color .25s,background-color .25s}.sp .sp-link.link[data-v-28528e42]:hover,.sp .sp-link.link[data-v-28528e42]:focus{outline:none;color:var(--vp-c-white);background-color:var(--vp-c-sponsor)}.sp-icon[data-v-28528e42]{margin-right:8px;width:16px;height:16px;fill:currentColor}.VPTeamMembers.small .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(224px,1fr))}.VPTeamMembers.small.count-1 .container[data-v-6cb0dbc4]{max-width:276px}.VPTeamMembers.small.count-2 .container[data-v-6cb0dbc4]{max-width:576px}.VPTeamMembers.small.count-3 .container[data-v-6cb0dbc4]{max-width:876px}.VPTeamMembers.medium .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(256px,1fr))}@media (min-width: 375px){.VPTeamMembers.medium .container[data-v-6cb0dbc4]{grid-template-columns:repeat(auto-fit,minmax(288px,1fr))}}.VPTeamMembers.medium.count-1 .container[data-v-6cb0dbc4]{max-width:368px}.VPTeamMembers.medium.count-2 .container[data-v-6cb0dbc4]{max-width:760px}.container[data-v-6cb0dbc4]{display:grid;gap:24px;margin:0 auto;max-width:1152px}svg[data-v-b64031fa]{margin-top:20px;width:100%;height:200px;cursor:pointer}.opt-wrap[data-v-6e6d96d1]{display:flex;flex-direction:column}.opt-wrap .opts[data-v-6e6d96d1]{display:flex;margin-top:10px}.opt-wrap .opts button[data-v-6e6d96d1]{color:#fff;border-radius:4px;padding:0 6px;margin-right:10px;border:1px solid #ccc;background-color:#4e9ef5}button[data-v-fcdef9a9]{color:#fff;border-radius:4px;padding:0 6px;margin-right:10px;border:1px solid #ccc;background-color:#6fadef}select[data-v-fcdef9a9]{margin:0 16px 0 6px;border:1px solid #ccc;border-radius:3px;padding:0 4px}textarea[data-v-fcdef9a9],iframe[data-v-fcdef9a9]{width:100%;height:200px;margin-top:10px}img[data-v-fcdef9a9]{width:100%;height:200px}.demo[data-v-9caf4c6f]{font-size:14px;background:rgba(125,125,125,.04);padding:1em;margin-bottom:10px;border-radius:8px;position:relative}.demo .demo-source-link[data-v-9caf4c6f]{position:absolute;top:3px;right:6px;font-size:12px!important;margin:0}.loader[data-v-4fdc7ada]{position:relative;color:#a886f2;width:60px;height:60px}.loader div[data-v-4fdc7ada]{background-color:currentColor}.loader div[data-v-4fdc7ada]:nth-child(1){width:16px;height:16px;position:absolute;bottom:32%;left:18%;border-radius:50%;transform-origin:center bottom;animation:ball-jump-4fdc7ada .6s ease-in-out infinite}.loader div[data-v-4fdc7ada]:not(:nth-child(1)){width:20px;height:4px;position:absolute;top:0;right:0;transform:translate(60%);animation:ball-steps-4fdc7ada 1.8s linear infinite}.loader div[data-v-4fdc7ada]:nth-child(2){animation-delay:0s}.loader div[data-v-4fdc7ada]:nth-child(3){animation-delay:-.6s}.loader div[data-v-4fdc7ada]:nth-child(4){animation-delay:-1.2s}@keyframes ball-jump-4fdc7ada{0%{transform:scaleY(.7)}20%{transform:scale(.7,1.2)}40%{transform:scale(1)}50%{bottom:80%;transform:scale(1)}80%,90%{transform:scale(.7,1.2)}to{transform:scaleY(.7)}}@keyframes ball-steps-4fdc7ada{0%{top:0;right:0;opacity:0}50%{opacity:1}to{top:100%;right:100%;opacity:0}}.dark .tool-item .tool-icon[data-v-2525f4e1]{border:1px solid #555}.tool-item[data-v-2525f4e1]{width:90px;height:90px;border-radius:10px}.tool-item .tool-icon[data-v-2525f4e1]{width:60px;height:60px;margin:0 15px 5px;border:1px solid #eee;border-radius:8px;transition:all .2s ease-in-out}.tool-item .tool-icon[data-v-2525f4e1]:hover{border:1px solid var(--vp-c-green)}.tool-item .tool-name[data-v-2525f4e1]{width:100%;height:25px;line-height:25px;text-align:center;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0;transition:all .2s ease-in-out;color:transparent;background-clip:text;background:var(--vp-home-hero-name-background);-webkit-background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}.tool-item .tool-name[data-v-2525f4e1]:hover{background-clip:text;background:linear-gradient(135deg,#5fe687 10%,#04d1e7 100%);-webkit-background-clip:text;-webkit-text-fill-color:linear-gradient(135deg,#5fe687 10%,#04d1e7 100%)}.tool-wrap .tool-group-title[data-v-a04e210c]{font-size:20px;font-weight:600;padding:20px 15px 10px;background-clip:text;background:var(--vp-home-hero-name-background);-webkit-background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}.tool-wrap .tool-group[data-v-a04e210c]{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));grid-gap:10px}:root{--vp-home-hero-name-color: transparent;--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);--vp-home-hero-image-background-image: linear-gradient(120deg, #bd34fe, #41d1ff);--vp-home-hero-image-filter: blur(80px)}@keyframes rainbow{0%{--vp-c-brand-1: #00a98e;--vp-c-brand-light: #4ad1b4;--vp-c-brand-lighter: #78fadc;--vp-c-brand-dark: #008269;--vp-c-brand-darker: #005d47;--vp-c-brand-next: #009ff7}1.25%{--vp-c-brand-1: #00a996;--vp-c-brand-light: #4bd1bd;--vp-c-brand-lighter: #79fbe5;--vp-c-brand-dark: #008371;--vp-c-brand-darker: #005e4f;--vp-c-brand-next: #009dfa}2.5%{--vp-c-brand-1: #00a99f;--vp-c-brand-light: #4cd1c6;--vp-c-brand-lighter: #7afbee;--vp-c-brand-dark: #00837a;--vp-c-brand-darker: #005e56;--vp-c-brand-next: #009bfc}3.75%{--vp-c-brand-1: #00a9a7;--vp-c-brand-light: #4dd1cf;--vp-c-brand-lighter: #7bfbf8;--vp-c-brand-dark: #008382;--vp-c-brand-darker: #005e5e;--vp-c-brand-next: #0098fd}5%{--vp-c-brand-1: #00a9b0;--vp-c-brand-light: #4ed1d7;--vp-c-brand-lighter: #7dfaff;--vp-c-brand-dark: #00838a;--vp-c-brand-darker: #005e65;--vp-c-brand-next: #0096fd}6.25%{--vp-c-brand-1: #00a9b8;--vp-c-brand-light: #4fd1e0;--vp-c-brand-lighter: #7efaff;--vp-c-brand-dark: #008391;--vp-c-brand-darker: #005e6d;--vp-c-brand-next: #0093fd}7.5%{--vp-c-brand-1: #00a9c0;--vp-c-brand-light: #50d0e8;--vp-c-brand-lighter: #7ffaff;--vp-c-brand-dark: #008399;--vp-c-brand-darker: #005e74;--vp-c-brand-next: #2e90fc}8.75%{--vp-c-brand-1: #00a8c7;--vp-c-brand-light: #51d0f0;--vp-c-brand-lighter: #81f9ff;--vp-c-brand-dark: #0082a0;--vp-c-brand-darker: #005e7b;--vp-c-brand-next: #4d8dfa}10%{--vp-c-brand-1: #00a8cf;--vp-c-brand-light: #52cff7;--vp-c-brand-lighter: #82f8ff;--vp-c-brand-dark: #0082a7;--vp-c-brand-darker: #005e81;--vp-c-brand-next: #638af8}11.25%{--vp-c-brand-1: #00a7d5;--vp-c-brand-light: #53cfff;--vp-c-brand-lighter: #84f8ff;--vp-c-brand-dark: #0081ae;--vp-c-brand-darker: #005d87;--vp-c-brand-next: #7587f5}12.5%{--vp-c-brand-1: #00a6dc;--vp-c-brand-light: #55ceff;--vp-c-brand-lighter: #85f7ff;--vp-c-brand-dark: #0081b4;--vp-c-brand-darker: #005d8d;--vp-c-brand-next: #8583f1}13.75%{--vp-c-brand-1: #00a6e2;--vp-c-brand-light: #56cdff;--vp-c-brand-lighter: #87f6ff;--vp-c-brand-dark: #0080b9;--vp-c-brand-darker: #005c93;--vp-c-brand-next: #9280ed}15%{--vp-c-brand-1: #00a4e7;--vp-c-brand-light: #57ccff;--vp-c-brand-lighter: #88f4ff;--vp-c-brand-dark: #007fbf;--vp-c-brand-darker: #005b98;--vp-c-brand-next: #9f7ce9}16.25%{--vp-c-brand-1: #00a3ec;--vp-c-brand-light: #58caff;--vp-c-brand-lighter: #89f3ff;--vp-c-brand-dark: #007ec3;--vp-c-brand-darker: #005b9c;--vp-c-brand-next: #aa78e3}17.5%{--vp-c-brand-1: #00a2f1;--vp-c-brand-light: #58c9ff;--vp-c-brand-lighter: #8af1ff;--vp-c-brand-dark: #007dc8;--vp-c-brand-darker: #0059a0;--vp-c-brand-next: #b574dd}18.75%{--vp-c-brand-1: #00a0f4;--vp-c-brand-light: #59c7ff;--vp-c-brand-lighter: #8bf0ff;--vp-c-brand-dark: #007bcb;--vp-c-brand-darker: #0058a3;--vp-c-brand-next: #be71d7}20%{--vp-c-brand-1: #009ff7;--vp-c-brand-light: #5ac5ff;--vp-c-brand-lighter: #8ceeff;--vp-c-brand-dark: #007ace;--vp-c-brand-darker: #0057a6;--vp-c-brand-next: #c76dd1}21.25%{--vp-c-brand-1: #009dfa;--vp-c-brand-light: #5ac3ff;--vp-c-brand-lighter: #8decff;--vp-c-brand-dark: #0078d0;--vp-c-brand-darker: #0055a8;--vp-c-brand-next: #cf69c9}22.5%{--vp-c-brand-1: #009bfc;--vp-c-brand-light: #5bc1ff;--vp-c-brand-lighter: #8de9ff;--vp-c-brand-dark: #0076d2;--vp-c-brand-darker: #0053aa;--vp-c-brand-next: #d566c2}23.75%{--vp-c-brand-1: #0098fd;--vp-c-brand-light: #5bbfff;--vp-c-brand-lighter: #8ee7ff;--vp-c-brand-dark: #0074d3;--vp-c-brand-darker: #0051ab;--vp-c-brand-next: #dc63ba}25%{--vp-c-brand-1: #0096fd;--vp-c-brand-light: #5bbcff;--vp-c-brand-lighter: #8ee4ff;--vp-c-brand-dark: #0071d4;--vp-c-brand-darker: #004fab;--vp-c-brand-next: #e160b3}26.25%{--vp-c-brand-1: #0093fd;--vp-c-brand-light: #5bb9ff;--vp-c-brand-lighter: #8ee1ff;--vp-c-brand-dark: #006fd3;--vp-c-brand-darker: #004dab;--vp-c-brand-next: #e65eab}27.5%{--vp-c-brand-1: #2e90fc;--vp-c-brand-light: #69b6ff;--vp-c-brand-lighter: #99deff;--vp-c-brand-dark: #006cd2;--vp-c-brand-darker: #004baa;--vp-c-brand-next: #e95ca2}28.75%{--vp-c-brand-1: #4d8dfa;--vp-c-brand-light: #7eb3ff;--vp-c-brand-lighter: #abdbff;--vp-c-brand-dark: #0069d1;--vp-c-brand-darker: #0048a9;--vp-c-brand-next: #ed5a9a}30%{--vp-c-brand-1: #638af8;--vp-c-brand-light: #8fb0ff;--vp-c-brand-lighter: #bbd7ff;--vp-c-brand-dark: #3066cf;--vp-c-brand-darker: #0045a7;--vp-c-brand-next: #ef5992}31.25%{--vp-c-brand-1: #7587f5;--vp-c-brand-light: #9fadff;--vp-c-brand-lighter: #cad4ff;--vp-c-brand-dark: #4963cc;--vp-c-brand-darker: #0941a4;--vp-c-brand-next: #f15989}32.5%{--vp-c-brand-1: #8583f1;--vp-c-brand-light: #aea9ff;--vp-c-brand-lighter: #d8d1ff;--vp-c-brand-dark: #5b5fc8;--vp-c-brand-darker: #2e3ea1;--vp-c-brand-next: #f25981}33.75%{--vp-c-brand-1: #9280ed;--vp-c-brand-light: #bca6ff;--vp-c-brand-lighter: #e6cdff;--vp-c-brand-dark: #6a5cc4;--vp-c-brand-darker: #413a9d;--vp-c-brand-next: #f25a79}35%{--vp-c-brand-1: #9f7ce9;--vp-c-brand-light: #c8a2ff;--vp-c-brand-lighter: #f2c9ff;--vp-c-brand-dark: #7758c0;--vp-c-brand-darker: #503598;--vp-c-brand-next: #f25c71}36.25%{--vp-c-brand-1: #aa78e3;--vp-c-brand-light: #d39eff;--vp-c-brand-lighter: #fec6ff;--vp-c-brand-dark: #8354bb;--vp-c-brand-darker: #5c3193;--vp-c-brand-next: #f15e69}37.5%{--vp-c-brand-1: #b574dd;--vp-c-brand-light: #de9bff;--vp-c-brand-lighter: #ffc2ff;--vp-c-brand-dark: #8d50b5;--vp-c-brand-darker: #662c8e;--vp-c-brand-next: #ef6061}38.75%{--vp-c-brand-1: #be71d7;--vp-c-brand-light: #e897ff;--vp-c-brand-lighter: #ffbfff;--vp-c-brand-dark: #964baf;--vp-c-brand-darker: #6f2688;--vp-c-brand-next: #ed635a}40%{--vp-c-brand-1: #c76dd1;--vp-c-brand-light: #f194fa;--vp-c-brand-lighter: #ffbcff;--vp-c-brand-dark: #9e47a9;--vp-c-brand-darker: #772082;--vp-c-brand-next: #eb6552}41.25%{--vp-c-brand-1: #cf69c9;--vp-c-brand-light: #f991f2;--vp-c-brand-lighter: #ffb9ff;--vp-c-brand-dark: #a643a2;--vp-c-brand-darker: #7e197c;--vp-c-brand-next: #e8694b}42.5%{--vp-c-brand-1: #d566c2;--vp-c-brand-light: #ff8deb;--vp-c-brand-lighter: #ffb6ff;--vp-c-brand-dark: #ac3f9b;--vp-c-brand-darker: #841075;--vp-c-brand-next: #e46c44}43.75%{--vp-c-brand-1: #dc63ba;--vp-c-brand-light: #ff8be3;--vp-c-brand-lighter: #ffb3ff;--vp-c-brand-dark: #b23b94;--vp-c-brand-darker: #89046f;--vp-c-brand-next: #e06f3d}45%{--vp-c-brand-1: #e160b3;--vp-c-brand-light: #ff88db;--vp-c-brand-lighter: #ffb1ff;--vp-c-brand-dark: #b7378c;--vp-c-brand-darker: #8d0068;--vp-c-brand-next: #db7336}46.25%{--vp-c-brand-1: #e65eab;--vp-c-brand-light: #ff86d2;--vp-c-brand-lighter: #ffaffb;--vp-c-brand-dark: #bb3485;--vp-c-brand-darker: #910060;--vp-c-brand-next: #d77630}47.5%{--vp-c-brand-1: #e95ca2;--vp-c-brand-light: #ff84ca;--vp-c-brand-lighter: #ffadf2;--vp-c-brand-dark: #be317d;--vp-c-brand-darker: #940059;--vp-c-brand-next: #d17a2a}48.75%{--vp-c-brand-1: #ed5a9a;--vp-c-brand-light: #ff83c1;--vp-c-brand-lighter: #fface9;--vp-c-brand-dark: #c12f75;--vp-c-brand-darker: #970052;--vp-c-brand-next: #cc7d24}50%{--vp-c-brand-1: #ef5992;--vp-c-brand-light: #ff82b8;--vp-c-brand-lighter: #ffabe0;--vp-c-brand-dark: #c32d6d;--vp-c-brand-darker: #98004b;--vp-c-brand-next: #c6811e}51.25%{--vp-c-brand-1: #f15989;--vp-c-brand-light: #ff82af;--vp-c-brand-lighter: #ffabd7;--vp-c-brand-dark: #c52d65;--vp-c-brand-darker: #9a0043;--vp-c-brand-next: #bf8418}52.5%{--vp-c-brand-1: #f25981;--vp-c-brand-light: #ff82a7;--vp-c-brand-lighter: #ffabce;--vp-c-brand-dark: #c52e5e;--vp-c-brand-darker: #9a003c;--vp-c-brand-next: #b98713}53.75%{--vp-c-brand-1: #f25a79;--vp-c-brand-light: #ff839e;--vp-c-brand-lighter: #ffacc5;--vp-c-brand-dark: #c62f56;--vp-c-brand-darker: #9a0035;--vp-c-brand-next: #b28a0f}55%{--vp-c-brand-1: #f25c71;--vp-c-brand-light: #ff8496;--vp-c-brand-lighter: #ffadbc;--vp-c-brand-dark: #c5314e;--vp-c-brand-darker: #99002e;--vp-c-brand-next: #ab8d0c}56.25%{--vp-c-brand-1: #f15e69;--vp-c-brand-light: #ff868d;--vp-c-brand-lighter: #ffaeb4;--vp-c-brand-dark: #c43447;--vp-c-brand-darker: #980027;--vp-c-brand-next: #a3900b}57.5%{--vp-c-brand-1: #ef6061;--vp-c-brand-light: #ff8885;--vp-c-brand-lighter: #ffb0ab;--vp-c-brand-dark: #c3373f;--vp-c-brand-darker: #970020;--vp-c-brand-next: #9c920d}58.75%{--vp-c-brand-1: #ed635a;--vp-c-brand-light: #ff8a7d;--vp-c-brand-lighter: #ffb2a3;--vp-c-brand-dark: #c13b38;--vp-c-brand-darker: #940619;--vp-c-brand-next: #949510}60%{--vp-c-brand-1: #eb6552;--vp-c-brand-light: #ff8d76;--vp-c-brand-lighter: #ffb59b;--vp-c-brand-dark: #be3e31;--vp-c-brand-darker: #921111;--vp-c-brand-next: #8b9715}61.25%{--vp-c-brand-1: #e8694b;--vp-c-brand-light: #ff8f6e;--vp-c-brand-lighter: #ffb794;--vp-c-brand-dark: #bb4229;--vp-c-brand-darker: #8f1908;--vp-c-brand-next: #83991b}62.5%{--vp-c-brand-1: #e46c44;--vp-c-brand-light: #ff9367;--vp-c-brand-lighter: #ffba8c;--vp-c-brand-dark: #b74622;--vp-c-brand-darker: #8c1f00;--vp-c-brand-next: #7a9b21}63.75%{--vp-c-brand-1: #e06f3d;--vp-c-brand-light: #ff9661;--vp-c-brand-lighter: #ffbd86;--vp-c-brand-dark: #b44a1a;--vp-c-brand-darker: #882500;--vp-c-brand-next: #719d27}65%{--vp-c-brand-1: #db7336;--vp-c-brand-light: #ff995a;--vp-c-brand-lighter: #ffc17f;--vp-c-brand-dark: #af4e11;--vp-c-brand-darker: #842a00;--vp-c-brand-next: #679e2e}66.25%{--vp-c-brand-1: #d77630;--vp-c-brand-light: #ff9c54;--vp-c-brand-lighter: #ffc47a;--vp-c-brand-dark: #ab5206;--vp-c-brand-darker: #802f00;--vp-c-brand-next: #5da035}67.5%{--vp-c-brand-1: #d17a2a;--vp-c-brand-light: #fea04f;--vp-c-brand-lighter: #ffc774;--vp-c-brand-dark: #a55600;--vp-c-brand-darker: #7b3300;--vp-c-brand-next: #51a13c}68.75%{--vp-c-brand-1: #cc7d24;--vp-c-brand-light: #f8a34a;--vp-c-brand-lighter: #ffca70;--vp-c-brand-dark: #a05900;--vp-c-brand-darker: #773700;--vp-c-brand-next: #44a244}70%{--vp-c-brand-1: #c6811e;--vp-c-brand-light: #f2a646;--vp-c-brand-lighter: #ffce6c;--vp-c-brand-dark: #9b5d00;--vp-c-brand-darker: #713b00;--vp-c-brand-next: #34a44b}71.25%{--vp-c-brand-1: #bf8418;--vp-c-brand-light: #ebaa42;--vp-c-brand-lighter: #ffd168;--vp-c-brand-dark: #956000;--vp-c-brand-darker: #6c3e00;--vp-c-brand-next: #1ba553}72.5%{--vp-c-brand-1: #b98713;--vp-c-brand-light: #e4ad3f;--vp-c-brand-lighter: #ffd466;--vp-c-brand-dark: #8e6300;--vp-c-brand-darker: #674100;--vp-c-brand-next: #00a65b}73.75%{--vp-c-brand-1: #b28a0f;--vp-c-brand-light: #ddb03d;--vp-c-brand-lighter: #ffd764;--vp-c-brand-dark: #886600;--vp-c-brand-darker: #614400;--vp-c-brand-next: #00a663}75%{--vp-c-brand-1: #ab8d0c;--vp-c-brand-light: #d5b33c;--vp-c-brand-lighter: #ffda63;--vp-c-brand-dark: #816900;--vp-c-brand-darker: #5b4700;--vp-c-brand-next: #00a76c}76.25%{--vp-c-brand-1: #a3900b;--vp-c-brand-light: #cdb63c;--vp-c-brand-lighter: #f8dd63;--vp-c-brand-dark: #7a6b00;--vp-c-brand-darker: #554900;--vp-c-brand-next: #00a874}77.5%{--vp-c-brand-1: #9c920d;--vp-c-brand-light: #c5b83d;--vp-c-brand-lighter: #f0e064;--vp-c-brand-dark: #736e00;--vp-c-brand-darker: #4e4b00;--vp-c-brand-next: #00a87d}78.75%{--vp-c-brand-1: #949510;--vp-c-brand-light: #bdbb3e;--vp-c-brand-lighter: #e7e366;--vp-c-brand-dark: #6c7000;--vp-c-brand-darker: #474d00;--vp-c-brand-next: #00a985}80%{--vp-c-brand-1: #8b9715;--vp-c-brand-light: #b4bd41;--vp-c-brand-lighter: #dee668;--vp-c-brand-dark: #647200;--vp-c-brand-darker: #404f00;--vp-c-brand-next: #00a98e}81.25%{--vp-c-brand-1: #83991b;--vp-c-brand-light: #abc045;--vp-c-brand-lighter: #d4e86c;--vp-c-brand-dark: #5c7400;--vp-c-brand-darker: #385100;--vp-c-brand-next: #00a996}82.5%{--vp-c-brand-1: #7a9b21;--vp-c-brand-light: #a2c249;--vp-c-brand-lighter: #cbea70;--vp-c-brand-dark: #537600;--vp-c-brand-darker: #2f5200;--vp-c-brand-next: #00a99f}83.75%{--vp-c-brand-1: #719d27;--vp-c-brand-light: #98c44e;--vp-c-brand-lighter: #c1ec75;--vp-c-brand-dark: #4a7700;--vp-c-brand-darker: #255300;--vp-c-brand-next: #00a9a7}85%{--vp-c-brand-1: #679e2e;--vp-c-brand-light: #8ec654;--vp-c-brand-lighter: #b7ee7a;--vp-c-brand-dark: #407900;--vp-c-brand-darker: #185500;--vp-c-brand-next: #00a9b0}86.25%{--vp-c-brand-1: #5da035;--vp-c-brand-light: #84c75a;--vp-c-brand-lighter: #acf080;--vp-c-brand-dark: #357a0a;--vp-c-brand-darker: #015600;--vp-c-brand-next: #00a9b8}87.5%{--vp-c-brand-1: #51a13c;--vp-c-brand-light: #79c961;--vp-c-brand-lighter: #a1f287;--vp-c-brand-dark: #277b16;--vp-c-brand-darker: #005700;--vp-c-brand-next: #00a9c0}88.75%{--vp-c-brand-1: #44a244;--vp-c-brand-light: #6dca68;--vp-c-brand-lighter: #96f48e;--vp-c-brand-dark: #117c1f;--vp-c-brand-darker: #005700;--vp-c-brand-next: #00a8c7}90%{--vp-c-brand-1: #34a44b;--vp-c-brand-light: #60cc70;--vp-c-brand-lighter: #89f595;--vp-c-brand-dark: #007d28;--vp-c-brand-darker: #005801;--vp-c-brand-next: #00a8cf}91.25%{--vp-c-brand-1: #1ba553;--vp-c-brand-light: #51cd77;--vp-c-brand-lighter: #7cf69d;--vp-c-brand-dark: #007e30;--vp-c-brand-darker: #00590d;--vp-c-brand-next: #00a7d5}92.5%{--vp-c-brand-1: #00a65b;--vp-c-brand-light: #48ce80;--vp-c-brand-lighter: #75f7a6;--vp-c-brand-dark: #007f38;--vp-c-brand-darker: #005917;--vp-c-brand-next: #00a6dc}93.75%{--vp-c-brand-1: #00a663;--vp-c-brand-light: #48cf88;--vp-c-brand-lighter: #75f8ae;--vp-c-brand-dark: #008040;--vp-c-brand-darker: #005a20;--vp-c-brand-next: #00a6e2}95%{--vp-c-brand-1: #00a76c;--vp-c-brand-light: #49cf91;--vp-c-brand-lighter: #76f9b7;--vp-c-brand-dark: #008049;--vp-c-brand-darker: #005b28;--vp-c-brand-next: #00a4e7}96.25%{--vp-c-brand-1: #00a874;--vp-c-brand-light: #49d099;--vp-c-brand-lighter: #76f9c0;--vp-c-brand-dark: #008151;--vp-c-brand-darker: #005c30;--vp-c-brand-next: #00a3ec}97.5%{--vp-c-brand-1: #00a87d;--vp-c-brand-light: #49d0a2;--vp-c-brand-lighter: #77fac9;--vp-c-brand-dark: #008159;--vp-c-brand-darker: #005c37;--vp-c-brand-next: #00a2f1}98.75%{--vp-c-brand-1: #00a985;--vp-c-brand-light: #4ad1ab;--vp-c-brand-lighter: #77fad3;--vp-c-brand-dark: #008261;--vp-c-brand-darker: #005d3f;--vp-c-brand-next: #00a0f4}to{--vp-c-brand-1: #00a98e;--vp-c-brand-light: #4ad1b4;--vp-c-brand-lighter: #78fadc;--vp-c-brand-dark: #008269;--vp-c-brand-darker: #005d47;--vp-c-brand-next: #009ff7}}:root{--vp-c-brand-1: #00a98e;--vp-c-brand-light: #4ad1b4;--vp-c-brand-lighter: #78fadc;--vp-c-brand-dark: #008269;--vp-c-brand-darker: #005d47;--vp-c-brand-next: #009ff7;animation:rainbow 50s linear infinite}@media (prefers-reduced-motion: reduce){:root{animation:none!important}}::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}::view-transition-old(root),.dark::view-transition-new(root){z-index:1}::view-transition-new(root),.dark::view-transition-old(root){z-index:9999}.dark .vp-doc blockquote{background-color:#56475769;border-left-color:#d2a3f6}.vp-doc blockquote{background-color:#f8efffb0;border-left-color:#d2a3f6}.custom-block.details{background-color:#f3f3f3}.dark .custom-block.details{background-color:var(--vp-custom-block-details-bg)}.container .title{color:transparent;background:var(--vp-home-hero-name-background);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}.container .outline-marker{width:2px}.has-outline .outline-title{font-size:14px}.has-outline .outline-link.active{color:var(--vp-c-brand-1)}.link .box .icon{transition:transform .3s ease-in-out}.link:hover .box .icon{transform:scale(1.1);background-color:#7de4c34b}.DocSearch-Button{display:flex;justify-content:center;align-items:center;margin:0;padding:0;width:32px;height:32px;border-radius:4px;background:transparent;transition:border-color .25s}@media (min-width: 768px){.DocSearch-Button{justify-content:flex-start;border:1px solid transparent;border-radius:8px;padding:0 10px 0 12px;width:100%;height:40px;background-color:var(--vp-c-bg-alt)}}@media (max-width: 768px){.DocSearch-Button-Keys{display:none}.VPNavBarHamburger{height:32px!important;width:32px!important;border-radius:4px}}.content img{box-shadow:0 0 3px #0003;transition:all .3s}.content img:hover{box-shadow:0 0 6px #0003;transform:translateY(-2px)}.vp-doc .details.custom-block div[class*=language-]+div[class*=language-]{margin-top:8px}.VPLocalSearchBox[data-v-6d2f2a19]{position:fixed;z-index:100;top:0;right:0;bottom:0;left:0;display:flex}.backdrop[data-v-6d2f2a19]{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--vp-backdrop-bg-color);transition:opacity .5s}.shell[data-v-6d2f2a19]{position:relative;padding:12px;margin:64px auto;display:flex;flex-direction:column;gap:16px;background:var(--vp-local-search-bg);width:min(100vw - 60px,900px);height:min-content;max-height:min(100vh - 128px,900px);border-radius:6px}@media (max-width: 767px){.shell[data-v-6d2f2a19]{margin:0;width:100vw;height:100vh;max-height:none;border-radius:0}}.search-bar[data-v-6d2f2a19]{border:1px solid var(--vp-c-divider);border-radius:4px;display:flex;align-items:center;padding:0 12px;cursor:text}@media (max-width: 767px){.search-bar[data-v-6d2f2a19]{padding:0 8px}}.search-bar[data-v-6d2f2a19]:focus-within{border-color:var(--vp-c-brand-1)}.search-icon[data-v-6d2f2a19]{margin:8px}@media (max-width: 767px){.search-icon[data-v-6d2f2a19]{display:none}}.search-input[data-v-6d2f2a19]{padding:6px 12px;font-size:inherit;width:100%}@media (max-width: 767px){.search-input[data-v-6d2f2a19]{padding:6px 4px}}.search-actions[data-v-6d2f2a19]{display:flex;gap:4px}@media (any-pointer: coarse){.search-actions[data-v-6d2f2a19]{gap:8px}}@media (min-width: 769px){.search-actions.before[data-v-6d2f2a19]{display:none}}.search-actions button[data-v-6d2f2a19]{padding:8px}.search-actions button[data-v-6d2f2a19]:not([disabled]):hover,.toggle-layout-button.detailed-list[data-v-6d2f2a19]{color:var(--vp-c-brand-1)}.search-actions button.clear-button[data-v-6d2f2a19]:disabled{opacity:.37}.search-keyboard-shortcuts[data-v-6d2f2a19]{font-size:.8rem;opacity:75%;display:flex;flex-wrap:wrap;gap:16px;line-height:14px}.search-keyboard-shortcuts span[data-v-6d2f2a19]{display:flex;align-items:center;gap:4px}@media (max-width: 767px){.search-keyboard-shortcuts[data-v-6d2f2a19]{display:none}}.search-keyboard-shortcuts kbd[data-v-6d2f2a19]{background:rgba(128,128,128,.1);border-radius:4px;padding:3px 6px;min-width:24px;display:inline-block;text-align:center;vertical-align:middle;border:1px solid rgba(128,128,128,.15);box-shadow:0 2px 2px #0000001a}.results[data-v-6d2f2a19]{display:flex;flex-direction:column;gap:6px;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain}.result[data-v-6d2f2a19]{display:flex;align-items:center;gap:8px;border-radius:4px;transition:none;line-height:1rem;border:solid 2px var(--vp-local-search-result-border);outline:none}.result>div[data-v-6d2f2a19]{margin:12px;width:100%;overflow:hidden}@media (max-width: 767px){.result>div[data-v-6d2f2a19]{margin:8px}}.titles[data-v-6d2f2a19]{display:flex;flex-wrap:wrap;gap:4px;position:relative;z-index:1001;padding:2px 0}.title[data-v-6d2f2a19]{display:flex;align-items:center;gap:4px}.title.main[data-v-6d2f2a19]{font-weight:500}.title-icon[data-v-6d2f2a19]{opacity:.5;font-weight:500;color:var(--vp-c-brand-1)}.title svg[data-v-6d2f2a19]{opacity:.5}.result.selected[data-v-6d2f2a19]{--vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);border-color:var(--vp-local-search-result-selected-border)}.excerpt-wrapper[data-v-6d2f2a19]{position:relative}.excerpt[data-v-6d2f2a19]{opacity:75%;pointer-events:none;max-height:140px;overflow:hidden;position:relative;opacity:.5;margin-top:4px}.result.selected .excerpt[data-v-6d2f2a19]{opacity:1}.excerpt[data-v-6d2f2a19] *{font-size:.8rem!important;line-height:130%!important}.titles[data-v-6d2f2a19] mark,.excerpt[data-v-6d2f2a19] mark{background-color:var(--vp-local-search-highlight-bg);color:var(--vp-local-search-highlight-text);border-radius:2px;padding:0 2px}.excerpt[data-v-6d2f2a19] .vp-code-group .tabs{display:none}.excerpt[data-v-6d2f2a19] .vp-code-group div[class*=language-]{border-radius:8px!important}.excerpt-gradient-bottom[data-v-6d2f2a19]{position:absolute;bottom:-1px;left:0;width:100%;height:8px;background:linear-gradient(transparent,var(--vp-local-search-result-bg));z-index:1000}.excerpt-gradient-top[data-v-6d2f2a19]{position:absolute;top:-1px;left:0;width:100%;height:8px;background:linear-gradient(var(--vp-local-search-result-bg),transparent);z-index:1000}.result.selected .titles[data-v-6d2f2a19],.result.selected .title-icon[data-v-6d2f2a19]{color:var(--vp-c-brand-1)!important}.no-results[data-v-6d2f2a19]{font-size:.9rem;text-align:center;padding:12px}svg[data-v-6d2f2a19]{flex:none} diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d5f707fa751979dfbc727e129d621b25e842f8cc GIT binary patch literal 4286 zcmc(jX;f9`6^7~LvQ1KBZFHHzn%Fv}wW-$Gwwk6IH7aoyXN?1*Afh5DQJiqXnMpuF z0a2Mn6cp!K;uvFGYSn0rNxMv!LFEE|Pv3L7_kshawm*7U-@S)(4)=T5``!E9;O6!N zebue&X1%&4zwG8#)6LDTp_VSWwb!z)+YjBV*Q9KfU2t>5I*Lmn{}RS`8|K4Jm=88% zI;UVdrepq^iRrKv^QRn4+Z~uzd6?$AFn`Q{{?%ePrteYMauXhCPsiRS^%Q1k0;czR zOwUA2kBwyvUBu8S4fCFZ;m_jxUm2Q;yUiZVs>@{z2QOkq$6*G>Vg~5FuNZoX#a#^D z6pJof91IzXLl(wjXt!N)$i=kyFXPaxjDgKJF!S^~4v)YLi^dEVgU32dKQZ(c!-q+j z?qcXFhWAr3e-p#IV)#pT8AEG}VdwMb!OC4zu`3s5g7zLAh8Y|0-?bLeCcvyNEzXCIE6=sYWJ`&4tF$@vIz_pnEV(7EMp$RcK zbVoBO$>Tc zmp1n;bYFdoA7?>TF*sKho&QMJUP~%wvG-*PTklaUlyJPz_sLLooh4)r$KIPR`{ zmDR@VS(uq(m@yX>RA%+Fi#R`8LU31&c6TszOd-YR1U2&vzZB!9 zac7{V{OhrP$r6896aXP&nENp%Sox492vjU8(WPx{Bm)w!Q)4f@B6&B=(f*z)0=s{y zXZJ{kuABILP#%pHo0s+69Q6y@$vfJJp=G&;vV1axIvJ*mA&BDHv-xV?GKzv!o70pJ zyC%wYX&WDgNAfjZ*$=h$LE|0Te?mI+lXp1!CGybQ{jzA2dY9^YZqm|gnD+AV$2^o( zlVF7ymQIDm(-en564z$ZX6GFiuisBekoFI7GFZ9{#pbh;L7T5pODU~=0N&pDfX^mM z`vcXt9sQD?3EUo-PTP#T)X;N&%de_FDtKsHd8qu02p?GOD+WIYgFgXjN2z%X+UDQk zX2^1w@u((je#;n~dX?IT;q^oCyL|2MC*2K^ci8*oI_MM6g)v)clKX&KdS=1G3m{EA z?x94Fhe&S-n+Pi{20!AGGO436rNQA6@*@&prnG6-rFxZW!!|XPq3M6;H9b@32>gDJ z_V-uLM_4{?d1x&3k0oX10e*GR*jM^AJ=j@ZZufD`RhEypmuA;`LW~zgi6Pu#@a1gG za+)44q>kFg9JdTkY zuk)(zx5_Kz%1AZk?vA;t!feO-(Xei;gJFUge6WR0!7KL+bwAN(AAP{?=nWF^bXRTI zf-2GJuF@>wnC(dX z2sVfzP7JZ*V2#Bvfg>BjXnwqqw@yKq{kJ(69n3U>MKCNFTzoa%g<| zA-_@U=z8#LcEoMu%8C^%Og%*7lMiX2&#$l5^5}g&pDWExTnyezLA@$|^*%aDze%C{ z<>L-rdWhkX*-n~C9Riz&!Nw7gAcpucWtxcgqA+?g^K$p|+cTxqKc`%rDyH3uLf$^} zkVay%Rzt1U$M177B$kq?OSlsd#)_L24dt6=^$-b4FaNqY0efHeu^xTb# zgYsed_%miZvin1(2c(H%%TP#GJ}gbRbUBWPQ4=_sxSVOb3+Qm_E=|rG8h<7htp+OV z{s(UIuepoJjLo3FRpv*(Tid#r} zN;082dkNZE!2FyeoQ;UG>++M;>j>U@l0z${aew*ve6}Nh0PN@u+xkJ4&Rq=B zgiDvwguOP@t0Gh%tJEu2sBbTuqMq%q<`(dXhcZL+gv-Yto9$flrDnSkF;JkMztbIZ z#gHS0tzxiiqHo}7sL1J z(n~#C3@-ngT<)O@)TiuoRmIuP;h~e1kExpJq#OI+-RQ6wzL80vR2=sx2X=-Ex=fQU powZ@tLYrYK9-mBu_go?OWd+KohAK?G>{%<6N=Q98R literal 0 HcmV?d00001 diff --git a/hashmap.json b/hashmap.json new file mode 100644 index 00000000..5db0ec71 --- /dev/null +++ b/hashmap.json @@ -0,0 +1 @@ +{"backend_nodejs_node大文件上传.md":"84c9f765","backend_server_docker学习笔记.md":"d29feca6","backend_server_nginx学习笔记.md":"9d658cc4","framework_angular_angular基础总结一.md":"25af9886","framework_vue_vue3补漏笔记.md":"6422a5f9","framework_react_react基础总结一.md":"fc5d41af","framework_vue_vite原理学习.md":"8895a11d","backend_nodejs_mongodb笔记.md":"eb6021c2","backend_nodejs_node简单上传文件.md":"faa27b4e","framework_vue_列表最后一条数据删除处理.md":"9f59b85b","frontend_javascript_代码分支优化.md":"e8fda00c","frontend_git_git常用操作.md":"a0e87468","frontend_git_配置多个平台ssh.md":"49289c60","frontend_javascript_图片懒加载.md":"3d5465d0","framework_vue_分页与搜索条件记录并回显优化.md":"8805bdc2","frontend_javascript_基础复习一.md":"a8906ce7","framework_angular_angular基础总结三.md":"574a1956","frontend_javascript_基础复习二.md":"8f89af07","interview_css_高级面试题.md":"63a54546","frontend_shell_自动部署脚本.md":"7ce896dd","interview_brower_事件循环机制.md":"9f053692","frontend_typescript_进阶使用技巧.md":"21fda5ca","interview_css_进阶面试题.md":"6b9b42f1","interview_css_基础面试题.md":"b72bdb12","frontend_typescript_配置文件详解.md":"7a55465d","frontend_javascript_正则表达式.md":"a9560fb8","frontend_javascript_获取目录结构.md":"f15b6a8f","goodtool_index.md":"2cde5d0e","interview_brower_计算机网络.md":"73c84072","interview_javascript_字符串常用方法.md":"4808f793","interview_brower_浏览器网页请求过程.md":"1acb73dd","frontend_css_grid布局学习笔记.md":"6624dd93","interview_javascript_原型与原型链.md":"4ad216b5","interview_javascript_promise相关.md":"1015a7af","backend_nodejs_node学习笔记.md":"f1b234ff","frontend_css_常用代码段.md":"083fb786","interview_index.md":"ff0a75dc","index.md":"4cc1630f","interview_vue_vue响应式原理.md":"2eeac150","frontend_javascript_高阶函数.md":"f3e81d0b","frontend_git_terminal终端美化.md":"6674896b","problem_graphical_antv使用总结.md":"10b596c9","frontend_javascript_async与await.md":"d21c9cb0","frontend_javascript_手写promise.md":"fbddbbf5","interview_vue_自定义指令.md":"3d2ea0a9","framework_angular_angular基础总结二.md":"0a8462a7","interview_vue_常见path区别.md":"56f4fc59","interview_javascript_进阶面试题.md":"c89e986d","problem_nuxt3_nuxt3项目踩坑.md":"e3bdda07","interview_vue_vue基础篇.md":"d7fd744f","interview_vue_前端项目优化.md":"3cd67a0e","problem_graphical_echarts问题总结.md":"fe67d408","problem_vitepress_vuepress踩坑记录.md":"d7553dcf","interview_vue_npm run xxx执行过程.md":"9da37746","interview_vue_vue声明周期.md":"4220f397","frontend_javascript_数组求集合.md":"9e71e873","frontend_typescript_初学笔记.md":"a7be054a","frontend_css_揭秘读书摘要.md":"3689a434","interview_javascript_高级面试题.md":"0abc2056","frontend_javascript_文件系统.md":"1488f287","problem_vitepress_vitepress踩坑记录.md":"007e02bc","interview_javascript_基础面试题.md":"0df982a7","problem_vueproject_vue项目踩坑一.md":"5d32b46a","frontend_javascript_数据去重.md":"f1eaba48","interview_vue_vue进阶篇.md":"786b9622","problem_index.md":"724652c6","problem_graphical_antv代码片段集锦.md":"3d28f150","frontend_javascript_常见算法.md":"0cd56de3"} diff --git a/index.html b/index.html new file mode 100644 index 00000000..3465a156 --- /dev/null +++ b/index.html @@ -0,0 +1,31 @@ + + + + + + ZerDocs | ZerDocs + + + + + + + + + + + + + + + + +