-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.json
1 lines (1 loc) · 412 KB
/
db.json
1
{"meta":{"version":1,"warehouse":"4.0.1"},"models":{"Asset":[{"_id":"source/images/about/default.jpg","path":"images/about/default.jpg","modified":0,"renderable":0},{"_id":"source/images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png","path":"images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png","modified":0,"renderable":0},{"_id":"source/images/post/bug-diary-cover.png","path":"images/post/bug-diary-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/ce25d5b1573d11ed95612cfda1215af5.png","path":"images/post/ce25d5b1573d11ed95612cfda1215af5.png","modified":0,"renderable":0},{"_id":"source/images/post/code-cover.png","path":"images/post/code-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/docker-cover.png","path":"images/post/docker-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/logo.jpg","path":"images/post/logo.jpg","modified":0,"renderable":0},{"_id":"source/images/post/music-cover.jpg","path":"images/post/music-cover.jpg","modified":0,"renderable":0},{"_id":"source/images/post/navigation-cover.png","path":"images/post/navigation-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/primevue-cover.png","path":"images/post/primevue-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/pypi-cover.png","path":"images/post/pypi-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/ssh-cover.png","path":"images/post/ssh-cover.png","modified":0,"renderable":0},{"_id":"source/images/post/selenium-cover.jpg","path":"images/post/selenium-cover.jpg","modified":0,"renderable":0},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/1.gif","path":"images/post/Use-Primevue-Steps-component-vue3/1.gif","modified":0,"renderable":0},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/2.jpg","path":"images/post/Use-Primevue-Steps-component-vue3/2.jpg","modified":0,"renderable":0},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/4.png","path":"images/post/Use-Primevue-Steps-component-vue3/4.png","modified":0,"renderable":0},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/3.png","path":"images/post/Use-Primevue-Steps-component-vue3/3.png","modified":0,"renderable":0},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/5.gif","path":"images/post/Use-Primevue-Steps-component-vue3/5.gif","modified":0,"renderable":0},{"_id":"source/images/post/docker-container-etc-hosts-file-reset-bug/01.png","path":"images/post/docker-container-etc-hosts-file-reset-bug/01.png","modified":0,"renderable":0},{"_id":"source/images/post/docker-container-etc-hosts-file-reset-bug/02.png","path":"images/post/docker-container-etc-hosts-file-reset-bug/02.png","modified":0,"renderable":0},{"_id":"node_modules/hexo-theme-fluid/source/js/color-schema.js","path":"js/color-schema.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/events.js","path":"js/events.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/boot.js","path":"js/boot.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/img-lazyload.js","path":"js/img-lazyload.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/local-search.js","path":"js/local-search.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/plugins.js","path":"js/plugins.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/utils.js","path":"js/utils.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/js/leancloud.js","path":"js/leancloud.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/css/gitalk.css","path":"css/gitalk.css","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/css/main.styl","path":"css/main.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/img/avatar.png","path":"img/avatar.png","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/css/highlight-dark.styl","path":"css/highlight-dark.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/css/highlight.styl","path":"css/highlight.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/img/default.png","path":"img/default.png","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/xml/local-search.xml","path":"xml/local-search.xml","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/img/fluid.png","path":"img/fluid.png","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/img/police_beian.png","path":"img/police_beian.png","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-fluid/source/img/loading.gif","path":"img/loading.gif","modified":0,"renderable":1}],"Cache":[{"_id":"source/_posts/hello-world.md","hash":"b44838d05a4420b8a87dbf60f5aa376d78c2e49d","modified":1667664233013},{"_id":"source/_posts/Use-Primevue-Steps-component-vue3.md","hash":"94b4efe49a17b01eec21bf2798e45849eb51b782","modified":1659410777137},{"_id":"source/_posts/docker-engine-install.md","hash":"b9e69f5b21dbe60c11c059ccb81a27f2d5fcaeb6","modified":1668134462355},{"_id":"source/_posts/selenium-waits-for-the-page-to-load.md","hash":"33e69efb087e2afdecb4270777ed35b1f830081c","modified":1660636674308},{"_id":"source/_posts/docker-container-etc-hosts-file-reset-bug.md","hash":"a49ce82c02220e6bf99994f94f513a2f21966d46","modified":1660646125921},{"_id":"source/_posts/song-list.md","hash":"a686885af4fbce305acdb968b94c1a6c0168b655","modified":1667381254823},{"_id":"source/about/index.md","hash":"bc94d0abe5b47f762890476d26eb2afb1fd76ccd","modified":1652349235363},{"_id":"source/_posts/代码片段.md","hash":"64029e687c0052c10d18e0dbfea66f5b81b1d4ca","modified":1671977744481},{"_id":"source/_posts/配置ssh免密登录.md","hash":"134848b9b0852d7250e1f576ab8faf987a999395","modified":1671977744481},{"_id":"source/images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png","hash":"e22f92eab7878253750c8ff8d6645547fa73ee37","modified":1668134582559},{"_id":"source/_posts/搭建私有pypi.md","hash":"ecd1da78ab154bca85d9747cbd1b983922c5ea53","modified":1667017145945},{"_id":"source/_posts/网站或工具.md","hash":"559f4ce727a86419517e4a0153fe04c553cee3a5","modified":1671977744481},{"_id":"source/images/post/code-cover.png","hash":"4d7334b0ed03f9f60dbef13379e811a145144545","modified":1668134710854},{"_id":"source/images/post/docker-cover.png","hash":"f5cb41e0493be3980b8587aa066183b7ba6a2abc","modified":1668134758098},{"_id":"source/images/post/logo.jpg","hash":"b9d125e88c1d2aa7ceff1576cbbd88f6ad263df8","modified":1668134966366},{"_id":"source/images/post/ce25d5b1573d11ed95612cfda1215af5.png","hash":"f449b238099e07cf5e59bcc5ca17233b05040fd9","modified":1667584683326},{"_id":"source/images/post/music-cover.jpg","hash":"3a5ea52019e57a91eeb5e00d0b4ef1dc7ae8ccee","modified":1668134822478},{"_id":"source/images/post/navigation-cover.png","hash":"b878a436332330e3c3bdee47a99539d160297fe2","modified":1667584683331},{"_id":"source/images/about/default.jpg","hash":"f9aa2b4faf3fb903804d7999dc727c4dfb2d9d80","modified":1667584683304},{"_id":"source/images/post/primevue-cover.png","hash":"d0c62b42849612315fd2479a8466e543199ed72c","modified":1668134857393},{"_id":"source/images/post/pypi-cover.png","hash":"eb792c2cf5a3484fa5572d3dd900db1bba1336db","modified":1668134897421},{"_id":"source/images/post/ssh-cover.png","hash":"88d9b06b045d5553aea6a466077b3c32fe2f4880","modified":1667664061480},{"_id":"source/images/post/selenium-cover.jpg","hash":"af78cfa35c019352b94e769c5545f5fe99354dea","modified":1667584683333},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/2.jpg","hash":"c846afd477f2c1ed2480e4139d06310beedcbc79","modified":1667584683310},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/4.png","hash":"00b31780fafea42a04fdd670522fe16865076576","modified":1667584683311},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/3.png","hash":"e847be54f496383149f8d21196e3305a980620f5","modified":1667584683311},{"_id":"source/images/post/docker-container-etc-hosts-file-reset-bug/02.png","hash":"a06ef830e54bb74cd374d7aa2b73fca51becdd2d","modified":1667584683328},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/1.gif","hash":"e94b991fcce41bb8eae8c861b8903465bd788c7e","modified":1667584683309},{"_id":"source/images/post/docker-container-etc-hosts-file-reset-bug/01.png","hash":"66d67a986292dec0d30c861cd2690bde5b70ab54","modified":1667584683327},{"_id":"source/images/post/bug-diary-cover.png","hash":"edf6ae32e07cf420d14ebd53f426565d52ec530b","modified":1668134643056},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_tag/tag.styl","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1667618983167},{"_id":"node_modules/hexo-theme-fluid/package.json","hash":"0bc354a01c5e6e9de43bf67456dc16c59d400139","modified":1667618979727},{"_id":"node_modules/hexo-theme-fluid/_config.yml","hash":"ebe26856c4cc286df3181136b5b391dd2e5f5ec7","modified":1667618983180},{"_id":"node_modules/hexo-theme-fluid/languages/en.yml","hash":"cb11b39f44ea069652c9647179606b6cecc98d50","modified":1667618983182},{"_id":"node_modules/hexo-theme-fluid/languages/es.yml","hash":"7112594259c88c04714be152af7fd377687dad40","modified":1667618983184},{"_id":"node_modules/hexo-theme-fluid/languages/zh-HK.yml","hash":"80ed400a7adaa92ea54fc7f5d534c9af795bed00","modified":1667618983187},{"_id":"node_modules/hexo-theme-fluid/languages/de.yml","hash":"0e7d455d9e004ff15d8924b7a0c35cea25ee5b1d","modified":1667618983182},{"_id":"node_modules/hexo-theme-fluid/languages/zh-CN.yml","hash":"f96a22f989897ecddc69d5867a206e1cf6b8f610","modified":1667618983186},{"_id":"node_modules/hexo-theme-fluid/languages/ja.yml","hash":"3dd6d20f8d26585a7c154a8e59fe8d5d902f4c6a","modified":1667618983185},{"_id":"node_modules/hexo-theme-fluid/languages/zh-TW.yml","hash":"596d031dff3826ae8e4ffc8931fff28977b73247","modified":1667618983188},{"_id":"node_modules/hexo-theme-fluid/layout/404.ejs","hash":"9569c5c8f67d2783f372f671c57b93a00dc63c2f","modified":1667618979080},{"_id":"node_modules/hexo-theme-fluid/languages/eo.yml","hash":"a556251cc50a5680578c03f1efbf252b1f4ab860","modified":1667618983183},{"_id":"node_modules/hexo-theme-fluid/layout/.DS_Store","hash":"e2295dbe42d85b294e6f3aeefaf3623bd31759ed","modified":1667618978723},{"_id":"node_modules/hexo-theme-fluid/README.md","hash":"6d752df6f2278033dc2512a7d5be22c8a8eb665a","modified":1667618979728},{"_id":"node_modules/hexo-theme-fluid/layout/archive.ejs","hash":"7c1f44005849791feae4abaa10fae4cb983d3277","modified":1667618979109},{"_id":"node_modules/hexo-theme-fluid/layout/about.ejs","hash":"163bee643e6a38912d3ae70923c83c48d57222e7","modified":1667618979083},{"_id":"node_modules/hexo-theme-fluid/layout/categories.ejs","hash":"13859726c27b6c79b5876ec174176d0f9c1ee164","modified":1667618979115},{"_id":"node_modules/hexo-theme-fluid/LICENSE","hash":"26f9356fd6e84b5a88df6d9014378f41b65ba209","modified":1667618979002},{"_id":"node_modules/hexo-theme-fluid/layout/links.ejs","hash":"1cac32ec4579aaf7b9fa39d317497331d4c5e1dd","modified":1667618979533},{"_id":"node_modules/hexo-theme-fluid/layout/layout.ejs","hash":"7e0023474128fbe4d68c467704c41f1712432415","modified":1667618979532},{"_id":"node_modules/hexo-theme-fluid/layout/index.ejs","hash":"b15d13877827e99e0ff783a6b13b13cca90bfe8c","modified":1667618979532},{"_id":"node_modules/hexo-theme-fluid/layout/page.ejs","hash":"ed5007a3feb8f14d3d2843271bfb298eb0c56219","modified":1667618979557},{"_id":"node_modules/hexo-theme-fluid/layout/category.ejs","hash":"f099161b738a16a32253f42085b5444f902018ed","modified":1667618979118},{"_id":"node_modules/hexo-theme-fluid/layout/tag.ejs","hash":"9d686364c4d16a1a9219471623af452035c5b966","modified":1667618979584},{"_id":"node_modules/hexo-theme-fluid/layout/post.ejs","hash":"505bcc06e55066b7cc5551d9ac0694e7713bfab5","modified":1667618979558},{"_id":"node_modules/hexo-theme-fluid/layout/tags.ejs","hash":"1d06af34b6cf1d8a20d2eb565e309326ceba309f","modified":1667618979585},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/category-chains.ejs","hash":"18309584aab83bc4deb20723ebad832149dd2e24","modified":1667618979117},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/archive-list.ejs","hash":"7520fbf91f762207c2ab06b2c293235cd5b23905","modified":1667618979088},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments.ejs","hash":"24ef242aa01e5f5bc397cf3f83ae48b1e8353dab","modified":1667618979119},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/category-list.ejs","hash":"a591fedbc5759fb00152304f9ea486dfba3a246a","modified":1667618979117},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/css.ejs","hash":"85f6e051550907681ab4ed2e268ac8f6e9ebf931","modified":1667618979500},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/head.ejs","hash":"776949aa697dffd54e9b1957d9245028879509a3","modified":1667618979529},{"_id":"node_modules/hexo-theme-fluid/scripts/.DS_Store","hash":"daec53fd4601c37ca272321ba2eb594d9b0a43ac","modified":1667618978724},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/footer.ejs","hash":"10ccfb8eef4e16182183c9a3e175c90d5b6397d3","modified":1667618979505},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/header.ejs","hash":"0d5e397d30051e5fbabe7b47cfd1f1e6a5820af1","modified":1667618979530},{"_id":"node_modules/hexo-theme-fluid/source/.DS_Store","hash":"e11e97632e6d13d5b9dccadcc514268f3c039508","modified":1667618978759},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/paginator.ejs","hash":"0f38a2c238169edcb63fc46c23bfc529ff3859b7","modified":1667618979557},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/search.ejs","hash":"70e1c929e084ca8a2648cedabf29b372511ea2b8","modified":1667618979583},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/scripts.ejs","hash":"da5810785105e5075861593c7ac22c7aa9665a72","modified":1667618979560},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/markdown-plugins.ejs","hash":"fc4bdf7de0cf1a66d0e5e4fba1b31d6f7ed49468","modified":1667618979534},{"_id":"node_modules/hexo-theme-fluid/scripts/events/index.js","hash":"79de5a379b28cad759a49048351c7f6b8915bd7d","modified":1667618979697},{"_id":"node_modules/hexo-theme-fluid/scripts/filters/post-filter.js","hash":"d516b9db63067f9ea9c72cc75ae4ff358417e77d","modified":1667618979717},{"_id":"node_modules/hexo-theme-fluid/scripts/filters/default-injects.js","hash":"b2013ae8e189cd07ebc8a2ff48a78e153345210f","modified":1667618979676},{"_id":"node_modules/hexo-theme-fluid/scripts/tags/button.js","hash":"3eb43a8cdea0a64576ad6b31b4df6c2bf5698d4c","modified":1667618979664},{"_id":"node_modules/hexo-theme-fluid/scripts/filters/locals.js","hash":"58d0fec976f6b1d35e7ea03edc45414088acf05c","modified":1667618979705},{"_id":"node_modules/hexo-theme-fluid/scripts/tags/group-image.js","hash":"4aeebb797026f1df25646a5d69f7fde79b1bcd26","modified":1667618979693},{"_id":"node_modules/hexo-theme-fluid/scripts/tags/checkbox.js","hash":"4938610c3543a921a341bc074626d511cb1a4b45","modified":1667618979665},{"_id":"node_modules/hexo-theme-fluid/scripts/tags/mermaid.js","hash":"75160561e1ef3603b6d2ad2938464ab1cb77fd38","modified":1667618979707},{"_id":"node_modules/hexo-theme-fluid/scripts/events/.DS_Store","hash":"80308812974d7cb7e001cd8f64ff9fced30ff139","modified":1667618978749},{"_id":"node_modules/hexo-theme-fluid/scripts/tags/label.js","hash":"f05a6d32cca79535b22907dc03edb9d3fa2d8176","modified":1667618979700},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/export-config.js","hash":"47e6dba7652a621a54067413490a11c8a89e3d7b","modified":1667618979689},{"_id":"node_modules/hexo-theme-fluid/scripts/tags/note.js","hash":"f52f3a005b41f48b4da274ac64710177c8d4502f","modified":1667618979710},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/date.js","hash":"9bda6382f61b40a20c24af466fe10c8366ebb74c","modified":1667618979674},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/page.js","hash":"4607607445233b3029ef20ed5e91de0da0a7f9c5","modified":1667618979713},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/engine.js","hash":"d3a231d106795ce99cb0bc77eb65f9ae44515933","modified":1667618979680},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/import.js","hash":"ca53e8dbf7d44cfd372cfa79ac60f35a7d5b0076","modified":1667618979697},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/injects.js","hash":"1ad2ae6b11bd8806ee7dd6eb7140d8b54a95d613","modified":1667618979699},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/scope.js","hash":"43620b0944ffb67ea1fa6cc838f65a7351222eb0","modified":1667618979719},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/wordcount.js","hash":"b917b893b1777e6ffcb53188f9f5644510e5f20d","modified":1667618979726},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/url.js","hash":"2a6a8288176d0e0f6ec008056bf2745a86e8943e","modified":1667618979723},{"_id":"node_modules/hexo-theme-fluid/scripts/generators/local-search.js","hash":"fc2c50405b771b06b7f6cfc4e9de97b992691555","modified":1667618979703},{"_id":"node_modules/hexo-theme-fluid/scripts/utils/compare-versions.js","hash":"dbbc928c914fc2bd242cd66aa0c45971aec13a5d","modified":1667618979669},{"_id":"node_modules/hexo-theme-fluid/scripts/generators/pages.js","hash":"d9971f15fbb6b775e3d31a1b9b45011959395010","modified":1667618979715},{"_id":"node_modules/hexo-theme-fluid/scripts/helpers/utils.js","hash":"226f99b465ff513de075a8e78b321d6cb62592ca","modified":1667618979723},{"_id":"node_modules/hexo-theme-fluid/scripts/utils/resolve.js","hash":"8c4a8b62aa8608f12f1e9046231dff04859dc3e9","modified":1667618979718},{"_id":"node_modules/hexo-theme-fluid/scripts/utils/object.js","hash":"33b57e4decdc5e75c518859f168c8ba80b2c665b","modified":1667618979712},{"_id":"node_modules/hexo-theme-fluid/scripts/utils/url-join.js","hash":"718aab5e7b2059a06b093ca738de420d9afa44ba","modified":1667618979722},{"_id":"node_modules/hexo-theme-fluid/scripts/utils/.DS_Store","hash":"df2fbeb1400acda0909a32c1cf6bf492f1121e07","modified":1667618978752},{"_id":"node_modules/hexo-theme-fluid/source/js/events.js","hash":"f05a569a9fd6da2fda69a2cf8e276ba81580faf3","modified":1667618979688},{"_id":"node_modules/hexo-theme-fluid/source/js/color-schema.js","hash":"ba63f7c3324bc1fdd050a90add9d8faaffc27e07","modified":1667618979667},{"_id":"node_modules/hexo-theme-fluid/source/js/boot.js","hash":"2848f8eb5081a7f0550fbd76dc06d3ff877f1913","modified":1667618979662},{"_id":"node_modules/hexo-theme-fluid/source/js/img-lazyload.js","hash":"cbdeca434ec4da51f488c821d51b4d23c73294af","modified":1667618979696},{"_id":"node_modules/hexo-theme-fluid/source/js/local-search.js","hash":"cebcda5991b6a9ab9307c69542389ce9013f04f7","modified":1667618979704},{"_id":"node_modules/hexo-theme-fluid/source/js/utils.js","hash":"45cc86f099db0a2c36ad49711ce66c2d598a2ab1","modified":1667618979726},{"_id":"node_modules/hexo-theme-fluid/source/js/plugins.js","hash":"2333494add51e5e1374602a4e81f0be36a05d4c2","modified":1667618979716},{"_id":"node_modules/hexo-theme-fluid/source/css/main.styl","hash":"855ae5fe229c51afa57f7645f6997a27a705d7e4","modified":1667618983160},{"_id":"node_modules/hexo-theme-fluid/source/js/leancloud.js","hash":"eff77c7a5c399fcaefda48884980571e15243fc9","modified":1667618979702},{"_id":"node_modules/hexo-theme-fluid/source/css/gitalk.css","hash":"a57b3cc8e04a0a4a27aefa07facf5b5e7bca0e76","modified":1667618979079},{"_id":"node_modules/hexo-theme-fluid/source/css/highlight.styl","hash":"a9efc52a646a9e585439c768557e3e3c9e3326dc","modified":1667618983155},{"_id":"node_modules/hexo-theme-fluid/source/css/highlight-dark.styl","hash":"45695ef75c31a4aa57324dd408b7e2327a337018","modified":1667618983152},{"_id":"node_modules/hexo-theme-fluid/source/xml/local-search.xml","hash":"8c96ba6a064705602ce28d096fd7dd9069630a55","modified":1667618983170},{"_id":"node_modules/hexo-theme-fluid/source/img/.DS_Store","hash":"df2fbeb1400acda0909a32c1cf6bf492f1121e07","modified":1667618978760},{"_id":"node_modules/hexo-theme-fluid/source/img/avatar.png","hash":"fe739a158cc128f70f780eb5fa96f388b81d478f","modified":1667618979774},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/changyan.ejs","hash":"c9b2d68ed3d375f1953e7007307d2a3f75ed6249","modified":1667618979118},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/cusdis.ejs","hash":"5f9dc012be27040bbe874d0c093c0d53958cc987","modified":1667618979501},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/giscus.ejs","hash":"95f8b866b158eff9352c381c243b332a155a5110","modified":1667618979506},{"_id":"node_modules/hexo-theme-fluid/source/img/police_beian.png","hash":"90efded6baa2dde599a9d6b1387973e8e64923ea","modified":1667618983124},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/disqus.ejs","hash":"aab4a4d24c55231a37db308ae94414319cecdd9b","modified":1667618979502},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/livere.ejs","hash":"2264758fed57542a7389c7aa9f00f1aefa17eb87","modified":1667618979533},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/remark42.ejs","hash":"d4e9532feeb02aed61bd15eda536b5b631454dac","modified":1667618979559},{"_id":"node_modules/hexo-theme-fluid/source/img/fluid.png","hash":"64b215db2cb3af98fe639e94537cb5209f959c78","modified":1667618983121},{"_id":"node_modules/hexo-theme-fluid/source/img/loading.gif","hash":"2d2fc0f947940f98c21afafef39ecf226a2e8d55","modified":1667618979661},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/twikoo.ejs","hash":"e6820fb7f13662c42f8433ec95404238f4c1860c","modified":1667618979585},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/utterances.ejs","hash":"c7ccf7f28308334a6da6f5425b141a24b5eca0e2","modified":1667618979586},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/gitalk.ejs","hash":"843bc141a4545eb20d1c92fb63c85d459b4271ec","modified":1667618979507},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/waline.ejs","hash":"12727da7cf3ac83443270f550be4d1c06135b52b","modified":1667618979588},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/comments/valine.ejs","hash":"19ba937553dddd317f827d682661a1066a7b1f30","modified":1667618979588},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/header/navigation.ejs","hash":"38990ed9dbccd88342ee4b4cb5e60818e9eb8e8a","modified":1667618979554},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/footer/beian.ejs","hash":"4fb9b5dd3f3e41a586d6af44e5069afe7c81fff2","modified":1667618979113},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/header/banner.ejs","hash":"e07757b59e7b89eea213d0e595cb5932f812fd32","modified":1667618979112},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/footer/statistics.ejs","hash":"454d8dd4c39f9494ebeb03ca0746f5bc122af76a","modified":1667618979584},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/fancybox.ejs","hash":"9d1ea2a46b8c8ad8c168594d578f40764818ef13","modified":1667618979504},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/code-widget.ejs","hash":"3a505cba37942badf62a56bbb8b605b72af330aa","modified":1667618979118},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/analytics.ejs","hash":"1327395a4dde1ea06c476b047fb110bcd269149f","modified":1667618979085},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/anchorjs.ejs","hash":"953552425f0b86c98d1026fdb04e716fdff356e7","modified":1667618979087},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/highlight.ejs","hash":"7529dd215b09d3557804333942377b9e20fa554e","modified":1667618979531},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/encrypt.ejs","hash":"cbcf6905f4990a22895a848e29dd4c05592a9043","modified":1667618979503},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/typed.ejs","hash":"51faef29f8e464bcb2e73049b428b88c8dd8b40a","modified":1667618979586},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/mermaid.ejs","hash":"3b3b0be9f7624ff72fbb2da6ae3663adcfb7d118","modified":1667618979551},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/nprogress.ejs","hash":"4c2d39ce816b8a6dcd6b53113c8695f8bd650a23","modified":1667618979555},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/category-bar.ejs","hash":"88420e83c0968f7da69aa423f42d3033891c9229","modified":1667618979116},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/plugins/math.ejs","hash":"94c1ce6e312932e876886ba24b082ae34515a038","modified":1667618979550},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/copyright.ejs","hash":"e74fb49526ddb14fee2c6360a560d17f57262ef7","modified":1667618979499},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/meta-bottom.ejs","hash":"7079b27a7bc15a7dfa9209f6be6051bdec49ebad","modified":1667618979551},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/footnote.js","hash":"2ec2ae03c79bb1ae7ac3fcf7e00fb52d1af2898d","modified":1667618979690},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/sidebar-right.ejs","hash":"d5fcc9b60e02f869a29a8c17a16a6028ecc1e6d8","modified":1667618979584},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/meta-top.ejs","hash":"ce6e9f578f4faa45840abddf8f46af3f4b69c177","modified":1667618979552},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/sidebar-left.ejs","hash":"9992c99b3eb728ad195970e1b84d665f2c8691c4","modified":1667618979584},{"_id":"node_modules/hexo-theme-fluid/layout/_partials/post/toc.ejs","hash":"91a1de823492d9225f9daa3ef59efbca345456a0","modified":1667618979585},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/compatible-configs.js","hash":"ef474d1fa5bbafc52619ced0f9dc7eaf2affb363","modified":1667618979670},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/injects.js","hash":"5ae4b07204683e54b5a1b74e931702bbce2ac23e","modified":1667618979698},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/merge-configs.js","hash":"7c944c43b2ece5dd84859bd9d1fe955d13427387","modified":1667618979706},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/highlight.js","hash":"0f02df2244e275595e72163498d42f42bcf0de5e","modified":1667618979696},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/hello.js","hash":"44c5eb97b98813a07c659d6afedd17fad63b1821","modified":1667618979695},{"_id":"node_modules/hexo-theme-fluid/scripts/events/lib/lazyload.js","hash":"9ba0d4bc224e22af8a5a48d6ff13e5a0fcfee2a4","modified":1667618979701},{"_id":"node_modules/hexo-theme-fluid/source/css/_functions/base.styl","hash":"2e46f3f4e2c9fe34c1ff1c598738fc7349ae8188","modified":1667618983135},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/pages.styl","hash":"b8e887bc7fb3b765a1f8ec9448eff8603a41984f","modified":1667618983162},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_about/about.styl","hash":"97fe42516ea531fdad771489b68aa8b2a7f6ae46","modified":1667618983126},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_archive/archive.styl","hash":"c475e6681546d30350eaed11f23081ecae80c375","modified":1667618983132},{"_id":"node_modules/hexo-theme-fluid/source/css/_mixins/base.styl","hash":"542e306ee9494e8a78e44d6d7d409605d94caeb3","modified":1667618983136},{"_id":"node_modules/hexo-theme-fluid/source/css/_variables/base.styl","hash":"4ed5f0ae105ef4c7dd92eaf652ceda176c38e502","modified":1667618983140},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/color-schema.styl","hash":"61279540c2623ea4bf93e40613d41380839b92d3","modified":1667618983147},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/keyframes.styl","hash":"94065ea50f5bef7566d184f2422f6ac20866ba22","modified":1667618983158},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/inline.styl","hash":"411a3fa3f924a87e00ff04d18b5c83283b049a4d","modified":1667618983157},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/base.styl","hash":"643284c567665f96915f0b64e59934dda315f74d","modified":1667618983138},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_category/category-bar.styl","hash":"99e8e25e84d513b869a17140f63a5c1e48a0e7e1","modified":1667618983142},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_category/category-list.styl","hash":"7edfe1b571ecca7d08f5f4dbcf76f4ffdcfbf0b5","modified":1667618983144},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_category/category-chain.styl","hash":"0cdf7ef50dfd0669d3b257821384ff31cd81b7c9","modified":1667618983143},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_tag/tags.styl","hash":"65bfc01c76abc927fa1a23bf2422892b0d566c3f","modified":1667618983168},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_post/highlight.styl","hash":"7054d79c9d5966fc57baf0adcdf3b19275987b62","modified":1667618983153},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_links/links.styl","hash":"5c7f2044e3f1da05a3229537c06bd879836f8d6e","modified":1667618983159},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_post/markdown.styl","hash":"1e3d3a82721e7c10bcfcecec6d81cf2979039452","modified":1667618983160},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_index/index.styl","hash":"0acbd71633bcc7191672ea4e1b2277bea350d73b","modified":1667618983156},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_post/comment.styl","hash":"780f3788e7357bcd3f3262d781cb91bb53976a93","modified":1667618983148},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_post/post-tag.styl","hash":"27f70062415ccf66a9b6f4952db124fc1471fda5","modified":1667618983165},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/anchorjs.styl","hash":"e0cebda4a6f499aff75e71417d88caa7ceb13b94","modified":1667618983130},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_post/post-page.styl","hash":"127bb5391370afe7fef2a297084d76406bc5e902","modified":1667618983164},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/board.styl","hash":"4397037fc3f0033dbe546c33cd9dbdabd8cb1632","modified":1667618983141},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/banner.styl","hash":"7a0bd629bc234fc75e3cc8e3715ffada92f09e73","modified":1667618983134},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/copyright.styl","hash":"26f71a9cd60d96bb0cb5bbdf58150b8e524d9707","modified":1667618983149},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/footnote.styl","hash":"ae9289cc89649af2042907f8a003303b987f3404","modified":1667618983151},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/footer.styl","hash":"2caaca71dd1ff63d583099ed817677dd267b457e","modified":1667618983150},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/ngrogress.styl","hash":"5d225357b4a58d46118e6616377168336ed44cb2","modified":1667618983161},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/header.styl","hash":"896179810e1ee986208ae2d57a44719f6b839bde","modified":1667618983151},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/code-widget.styl","hash":"b66ab013f0f37d724a149b85b3c7432afcf460ad","modified":1667618983146},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/modal.styl","hash":"adf6c1e5c8e1fb41c77ce6e2258001df61245aa2","modified":1667618983161},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/pagination.styl","hash":"8bb1b68e5f3552cb48c2ffa31edbc53646a8fb4c","modified":1667618983162},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/noscript.styl","hash":"0cf2f2bb44f456150d428016675d5876a9d2e2aa","modified":1667618983161},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/qrcode.styl","hash":"78704a94c0436097abfb0e0a57abeb3429c749b7","modified":1667618983165},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/search.styl","hash":"10f7e91a91e681fb9fe46f9df7707b9ef78707c8","modified":1667618983166},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/scroll-btn.styl","hash":"f0e429a27fa8a7658fcbddbb4d4dbe4afa12499a","modified":1667618983166},{"_id":"source/images/post/Use-Primevue-Steps-component-vue3/5.gif","hash":"355fc10a990461adb318be28adc371faf281c3ba","modified":1667584683316},{"_id":"node_modules/hexo-theme-fluid/source/css/_pages/_base/_widget/toc.styl","hash":"9e7452aa2372153f25d7a4675c9d36d281a65d24","modified":1667618983169},{"_id":"node_modules/hexo-theme-fluid/source/img/default.png","hash":"167a12978d80371cf578c8a2e45c24a2eb25b6fb","modified":1667618983058}],"Category":[{"name":"开发","_id":"clb4fek6o0003z0iw546f6hwn"},{"name":"建设","_id":"clb4fek6u0008z0iwejz34cu2"},{"name":"Bug日记","_id":"clb4fek6w000cz0iw4qrz1yb8"},{"name":"前端","parent":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek6z000jz0iwg39z2veu"},{"name":"其他","_id":"clb4fek73000pz0iwfg1k64ky"},{"name":"爬虫","parent":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek74000tz0iw6xqab26v"},{"name":"常用配置","parent":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek74000yz0iwhj62epp5"},{"name":"PrimeVue框架","parent":"clb4fek6z000jz0iwg39z2veu","_id":"clb4fek750014z0iw5qu20s1v"}],"Data":[],"Page":[{"title":"关于我","date":"2022-05-12T09:53:19.000Z","layout":"about","_content":"","source":"about/index.md","raw":"---\ntitle: 关于我\ndate: 2022-05-12 17:53:19\nlayout: about\n---\n","updated":"2022-05-12T09:53:55.363Z","path":"about/index.html","_id":"clb4fek6g0000z0iwetjgfp2b","comments":1,"content":"","site":{"data":{}},"wordcount":0,"excerpt":"","more":""}],"Post":[{"layout":"post","title":"Steps组件使用","index_img":"/images/post/primevue-cover.png","date":"2022-08-01T02:12:38.000Z","_content":"\n# PrimeVue框架--Steps组件使用\n\n\n## 1. 组件简介\n\n> **PrimeVue**\n> \n> Steps 组件是向导工作流中步骤的指示器。\n> \n> https://www.primefaces.org/primevue/steps\n\n通常称为 `步骤条`, `步进条`\n\n\n按理来说,组件的使用直接参考官方文档即可,不需要记录到博客。\n\n但是 PrimeVue 的步骤条与 Element 框架点区别,PrimeVue 的步骤条是基于 Vue Router 的,之前没有接触过,使用过程中踩了一两个坑,所以还是打算用博客的形式记录一下使用方法,供日后参考,而不是苦哈哈的再去研究官方文档💀\n\n\n## 2. 使用方法\n\n> **小提示**:\n> \n> 所有代码都基于Vue3项目,所以确保您拥有一个vue3项目\n>\n> 如果您没有,请使用 [Vue-CLI](https://cli.vuejs.org/zh/) 创建,参考:[https://cli.vuejs.org/zh/guide/creating-a-project.html](https://cli.vuejs.org/zh/guide/creating-a-project.html)\n\n\n**创建一个Vue3项目**\n```sh\n[mf~/project/demo] $ vue create primevue-steps\n```\n\n**选择Vue3选项**\n```sh\nVue CLI v4.5.15\n┌──────────────────────────────────────────┐\n│ │\n│ New version available 4.5.15 → 5.0.8 │\n│ Run npm i -g @vue/cli to update! │\n│ │\n└──────────────────────────────────────────┘\n\n? Please pick a preset: \n Default ([Vue 2] babel, eslint) \n❯ Default (Vue 3) ([Vue 3] babel, eslint) \n Manually select features \n```\n\n**等待创建完成**\n\n```sh\nVue CLI v4.5.15\n✨ Creating project in /home/mf/project/demo/primevue-steps.\n🗃 Initializing git repository...\n⚙️ Installing CLI plugins. This might take a while...\n\n\nadded 1300 packages in 1m\n🚀 Invoking generators...\n📦 Installing additional dependencies...\n\n\nadded 71 packages in 13s\n⚓ Running completion hooks...\n\n📄 Generating README.md...\n\n🎉 Successfully created project primevue-steps.\n👉 Get started with the following commands:\n\n $ cd primevue-steps\n $ npm run serve\n\n WARN Skipped git commit due to missing username and email in git config, or failed to sign commit.\nYou will need to perform the initial commit yourself.\n```\n\n创建完成后,切换到项目目录(`例子中是 /home/mf/project/demo/primevue-steps`)\n\n```sh\ncd primevue-steps\n```\n\n\n### 2.1 安装 Vue Router\n\n由于 steps组件 是基于 Vue Router 的,所以使用前需要安装 Vue Router\n\n```sh\nnpm install vue-router@4\n```\n\n```sh\n[mf~/project/demo/primevue-steps] (master) $ npm install vue-router@4\n\nadded 2 packages, and audited 1374 packages in 18s\n\n1 package is looking for funding\n run `npm fund` for details\n\n25 vulnerabilities (11 moderate, 7 high, 7 critical)\n\nTo address issues that do not require attention, run:\n npm audit fix\n\nTo address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n```\n\n### 2.2 安装 PrimeVue \n\n```sh\nnpm install primevue@^3.15.0 --save\nnpm install primeicons --save\n```\n\n```sh\n[mf~/project/demo/primevue-steps] (master) $ npm install primevue@^3.15.0 --save\n\nadded 2 packages, and audited 1376 packages in 17s\n\n1 package is looking for funding\n run `npm fund` for details\n\n25 vulnerabilities (11 moderate, 7 high, 7 critical)\n\nTo address issues that do not require attention, run:\n npm audit fix\n\nTo address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n[mf~/project/demo/primevue-steps] (master) $ npm install primeicons --save\n\nup to date, audited 1376 packages in 9s\n\n1 package is looking for funding\n run `npm fund` for details\n\n25 vulnerabilities (11 moderate, 7 high, 7 critical)\n\nTo address issues that do not require attention, run:\n npm audit fix\n\nTo address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n[mf~/project/demo/primevue-steps] (master) $ \n```\n\n### 2.2 创建测试视图(view)\n\n在 `primevue-steps/src/` 目录下创建目录 `views`,用于存储视图(`primevue-steps/src/views`),在此目录下创建视图文件 `TestView.vue`\n\n```html\n<template>\n <h3>PrimeVue Steps 组件测试视图</h3>\n</template>\n\n<script>\n export default {\n name: 'TestView',\n components: {},\n setup() {\n \n }\n }\n</script>\n```\n\n### 2.3 为项目引入路由并为测试视图创建一个路由\n\n在 `primevue-steps/src/` 目录下创建目录 `router`,用于存储路由文件(`primevue-steps/src/router`),在此目录下创建路由文件 `index.js`\n\n```js\nimport { createRouter, createWebHistory } from \"vue-router\";\nimport HelloWorld from \"@/components/HelloWorld\"\nimport TestView from \"@/views/TestView\"\n\n// 两个路由,根路由(/) 和 测试视图路由(/tv)\n// 根路由和默认的示例HelloWorld组件绑定,用于显示我们的首页\n// 测试视图路由和我们的测试视图绑定,用于显示我们的测试视图\nconst routes = [\n {\n name: \"index\",\n path: \"/\",\n component: HelloWorld\n }, {\n name: \"testView\",\n path: \"/tv\",\n component: TestView\n }\n]\n\nconst router = createRouter({\n history: createWebHistory(),\n routes\n})\n\nexport default router;\n```\n\n路由文件创建完成,在 `primevue-steps/src/main.js` 文件中导入并使用路由\n\n```js\nimport { createApp } from 'vue'\nimport App from './App.vue'\n// 导入路由\nimport router from '@/router'\n// 导入PrimeVue样式\nimport 'primeicons/primeicons.css'\nimport 'primevue/resources/primevue.min.css'\nimport 'primevue/resources/themes/saga-blue/theme.css'\n\n\ncreateApp(App).use(router).mount('#app')\n```\n\n最后在 `primevue-steps/src/App.vue` 中注释掉默认内容,插入 `<router-view></router-view>` 标签,路由所对应的组件/视图都将渲染到此处\n\n```html\n<template>\n <!-- <img alt=\"Vue logo\" src=\"./assets/logo.png\">\n <HelloWorld msg=\"Welcome to Your Vue.js App\"/> -->\n <router-view></router-view>\n</template>\n\n<script>\n// import HelloWorld from './components/HelloWorld.vue'\n\nexport default {\n name: 'App',\n components: {\n // HelloWorld\n }\n}\n</script>\n\n<style>\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n</style>\n\n```\n\n启动测试服务器\n\n```sh\n[mf~/project/demo/primevue-steps] (master) $ npm run serve\n\n DONE Compiled successfully in 300ms 11:39:34 AM\n\n\n App running at:\n - Local: http://localhost:8081/ \n - Network: http://192.168.8.7:8081/\n\n\n```\n\n![](/images/post/Use-Primevue-Steps-component-vue3/1.gif)\n\n\n### 2.4 在测试视图中引入Steps组件并使用\n\n> **知识点:**\n>\n> PrimeVue中Steps组件的步骤组件切换使用嵌套路由实现,关系图如下:\n\n![](/images/post/Use-Primevue-Steps-component-vue3/2.jpg)\n\n#### 2.4.1 在测试视图中使用steps组件\n\n```html\n<template>\n <h3>PrimeVue Steps 组件测试视图</h3>\n <!-- \n sreps组件本身 \n :model=\"stepsItems\" 绑定步骤信息,每个步骤项为一个对象,指定步骤名称和要跳转的子路由地址\n :readonly=\"true\" 只读步骤,步骤条不可点击,如果为false,则可以点击相应的步骤项跳转到的子路由\n -->\n <Steps :model=\"stepsItems\" :readonly=\"true\" />\n <!-- \n 嵌套路由渲染区, 用于渲染步骤组件\n :formData=\"formObject\" 向子路由传递数据。可选,一般用于给子路由的组件传递初始值,如果不需要可以忽略\n @prevPage=\"prevPage($event)\" 监听子路由prevPage事件, 用于跳转到上一页(上一步)\n @nextPage=\"nextPage($event)\" 监听子路由nextPage事件, 用于跳转到下一页(下一步)\n @complete=\"complete\" 监听子路由complete事件,该事件触发时表示步骤完成\n -->\n <router-view \n v-slot=\"{ Component }\" \n :formData=\"formObject\" \n @prevPage=\"prevPage($event)\" \n @nextPage=\"nextPage($event)\"\n @complete=\"complete($event)\"\n >\n <keep-alive>\n <component :is=\"Component\" />\n </keep-alive>\n </router-view>\n</template>\n\n<script>\nimport { ref } from 'vue'\n// 导入router, 用于控制子路由\nimport { useRouter } from 'vue-router'\n// 导入 steps 组件\nimport Steps from 'primevue/steps'\n\nexport default {\n name: 'TestView',\n components: { Steps },\n setup() {\n // 路由实例, 控制子由跳转\n const router = useRouter()\n // 步骤条信息\n const stepsItems = ref([\n { label: '步骤1', to: '/tv/p1' },\n { label: '步骤2', to: '/tv/p2' },\n { label: '步骤3', to: '/tv/p3' },\n ])\n // 数据\n const formObject = ref({\n msg: 'Steps数据'\n })\n\n /**\n * @function 子路由事件处理函数, 跳转到下一页(下一个步骤)\n * @param {*} data 子路由组件传递的数据\n */\n const nextPage = (data) => {\n // 这里进行子路由组件数据的处理\n // 这里为了演示只是向控制台打印传递的数据\n console.info(`Steps: ${stepsItems.value[data.value.index].label}传递的数据`, data.value)\n // 跳转到下一个步骤, 下一个步骤的路由信息由stepsItems定义\n router.push(stepsItems.value[data.value.index + 1].to);\n }\n\n /**\n * @function 子路由事件处理函数, 跳转到上一页(上一个步骤)\n * @param {*} data 子路由组件传递的数据\n */\n const prevPage = (data) => {\n router.push(stepsItems.value[data.value.index - 1].to);\n };\n\n /**\n * @function 子路由事件处理函数, 步骤完成\n * @param {*} data 子路由组件传递的数据\n */\n const complete = (data) => {\n // 这里做步骤完成后的操作, 这里为了演示只是进行了简单的提示,和打印控制台\n console.info(`Steps: ${stepsItems.value[data.value.index].label}传递的数据`, data.value)\n alert('步骤完成')\n };\n\n return {\n stepsItems, formObject,\n nextPage, prevPage, complete\n }\n }\n}\n</script>\n```\n\n访问 `/tv` ,可以看到步骤条已经创建。\n\n![](/images/post/Use-Primevue-Steps-component-vue3/3.png)\n\n\n#### 2.4.2 创建子路由组件\n\n在 `primevue-steps/src/components` 目录下创建路由文件三个组件提供个`steps`组件使用\n\n- P1.vue\n- P2.vue\n- P3.vue\n\n![](/images/post/Use-Primevue-Steps-component-vue3/4.png)\n\n**P1.vue**\n\n```html\n<template>\n <div>\n <h4>步骤一:/tv/p1</h4>\n <!-- 下一页控制按钮 -->\n <button @click=\"nextPage\">下一步</button>\n </div>\n</template>\n\n<script>\nimport {ref} from 'vue'\n\nexport default {\n name: 'P1',\n components: { },\n // 声明接收steps组件传递的数据\n props: {\n formData: Object\n },\n // 声明事件\n emits: ['prevPage', 'nextPage', 'complete'],\n\n setup(props, ctx) {\n console.log('步骤一, Steps传递的数据:', props.formData)\n\n // 当前组件的数据, nextPage事件发出时传递给Steps组件\n const data = ref({\n formData: {\n msg: '我是步骤一'\n },\n index: 0\n })\n\n /**\n * @function 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页\n */\n const nextPage = () => {\n ctx.emit('nextPage', data)\n }\n\n return {\n nextPage\n }\n }\n\n \n}\n</script>\n\n<style scoped>\n div {\n width: 100%;\n height: 100px;\n border-radius: 10px;\n margin-top: 10px;\n box-shadow: 0px 0px 10px 5px #666666;\n }\n</style>\n```\n\n**P2.vue**\n\n```html\n<template>\n <div>\n <h4>步骤二:/tv/p2</h4>\n <!-- 上一页,下一页控制按钮 -->\n <button @click=\"prevPage\">上一步</button>\n <button @click=\"nextPage\">下一步</button>\n </div>\n</template>\n\n<script>\nimport {ref} from 'vue'\n\nexport default {\n name: 'P2',\n components: { },\n // 声明接收steps组件传递的数据\n props: {\n formData: Object\n },\n // 声明事件\n emits: ['prevPage', 'nextPage', 'complete'],\n\n setup(props, ctx) {\n console.log('步骤二, Steps传递的数据:', props.formData)\n\n // 当前组件的数据, nextPage事件发出时传递给Steps组件\n const data = ref({\n formData: {\n msg: '我是步骤二'\n },\n index: 1\n })\n\n /**\n * @function 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页\n */\n const nextPage = () => {\n ctx.emit('nextPage', data)\n }\n\n /**\n * @function 向steps组件发出prevPage事件,让steps组件控制router跳转到上一页\n */\n const prevPage = () => {\n ctx.emit('prevPage', data)\n }\n\n return {\n nextPage, prevPage\n }\n }\n\n \n}\n</script>\n\n<style scoped>\n div {\n width: 100%;\n height: 100px;\n border-radius: 10px;\n margin-top: 10px;\n box-shadow: 0px 0px 10px 5px #666666;\n }\n</style>\n```\n\n**P3.vue**\n\n```html\n<template>\n <div>\n <h4>步骤三:/tv/p3</h4>\n <!-- 上一页,下一页控制按钮 -->\n <button @click=\"prevPage\">上一步</button>\n <button @click=\"complete\">完成/确定</button>\n </div>\n</template>\n\n<script>\nimport {ref} from 'vue'\n\nexport default {\n name: 'P3',\n components: { },\n // 声明接收steps组件传递的数据\n props: {\n formData: Object\n },\n // 声明事件\n emits: ['prevPage', 'nextPage', 'complete'],\n\n setup(props, ctx) {\n console.log('步骤三, Steps传递的数据:', props.formData)\n\n // 当前组件的数据, nextPage事件发出时传递给Steps组件\n const data = ref({\n formData: {\n msg: '我是步骤三'\n },\n index: 2\n })\n\n /**\n * @function 向steps组件发出prevPage事件,让steps组件控制router跳转到下一页\n */\n const prevPage = () => {\n ctx.emit('prevPage', data)\n }\n\n /**\n * @function 向steps组件发出complete事件,告知steps组件步骤完成\n */\n const complete = () => {\n ctx.emit('complete', data)\n }\n\n return {\n prevPage, complete\n }\n }\n\n \n}\n</script>\n\n<style scoped>\n div {\n width: 100%;\n height: 100px;\n border-radius: 10px;\n margin-top: 10px;\n box-shadow: 0px 0px 10px 5px #666666;\n }\n</style>\n```\n\n#### 2.4.3 为子路由组件指定路由地址\n\n修改路由文件 `primevue-steps/src/router/index.js`,为TestView视图添加子路由\n\n```js\nimport { createRouter, createWebHistory } from \"vue-router\";\nimport HelloWorld from \"@/components/HelloWorld\"\nimport TestView from \"@/views/TestView\"\n// 导入子路由组件\nimport P1 from \"@/components/P1\"\nimport P2 from \"@/components/P2\"\nimport P3 from \"@/components/P3\"\n\n\nconst routes = [\n {\n name: \"index\",\n path: \"/\",\n component: HelloWorld\n }, {\n name: \"testView\",\n path: \"/tv\",\n component: TestView,\n // setps组件子路由\n children: [\n {path: 'p1', component: P1},\n {path: 'p2', component: P2},\n {path: 'p3', component: P3},\n ]\n }\n]\n\nconst router = createRouter({\n history: createWebHistory(),\n routes\n})\n\nexport default router;\n```\n\n完成后刷新页面并访问路径 `/tv/p1`,即可看到步骤页\n\n![](/images/post/Use-Primevue-Steps-component-vue3/5.gif)\n\n\n## 3. 演示Demo\n\n文章中所用的测试Demo已经推送到github:[https://github.com/mangfu26/blog-share/tree/primevue-steps](https://github.com/mangfu26/blog-share/tree/primevue-steps)\n\n你可以使用以下命令克隆使用\n\n```sh\ngit clone -b primevue-steps https://github.com/mangfu26/blog-share.git primevue-steps\n```","source":"_posts/Use-Primevue-Steps-component-vue3.md","raw":"---\nlayout: post\ntitle: Steps组件使用\nindex_img: /images/post/primevue-cover.png\ndate: 2022-08-01 10:12:38\ncategories:\n- 开发\n- 前端\n- PrimeVue框架\ntags:\n- 前端\n- PrimeVue\n---\n\n# PrimeVue框架--Steps组件使用\n\n\n## 1. 组件简介\n\n> **PrimeVue**\n> \n> Steps 组件是向导工作流中步骤的指示器。\n> \n> https://www.primefaces.org/primevue/steps\n\n通常称为 `步骤条`, `步进条`\n\n\n按理来说,组件的使用直接参考官方文档即可,不需要记录到博客。\n\n但是 PrimeVue 的步骤条与 Element 框架点区别,PrimeVue 的步骤条是基于 Vue Router 的,之前没有接触过,使用过程中踩了一两个坑,所以还是打算用博客的形式记录一下使用方法,供日后参考,而不是苦哈哈的再去研究官方文档💀\n\n\n## 2. 使用方法\n\n> **小提示**:\n> \n> 所有代码都基于Vue3项目,所以确保您拥有一个vue3项目\n>\n> 如果您没有,请使用 [Vue-CLI](https://cli.vuejs.org/zh/) 创建,参考:[https://cli.vuejs.org/zh/guide/creating-a-project.html](https://cli.vuejs.org/zh/guide/creating-a-project.html)\n\n\n**创建一个Vue3项目**\n```sh\n[mf~/project/demo] $ vue create primevue-steps\n```\n\n**选择Vue3选项**\n```sh\nVue CLI v4.5.15\n┌──────────────────────────────────────────┐\n│ │\n│ New version available 4.5.15 → 5.0.8 │\n│ Run npm i -g @vue/cli to update! │\n│ │\n└──────────────────────────────────────────┘\n\n? Please pick a preset: \n Default ([Vue 2] babel, eslint) \n❯ Default (Vue 3) ([Vue 3] babel, eslint) \n Manually select features \n```\n\n**等待创建完成**\n\n```sh\nVue CLI v4.5.15\n✨ Creating project in /home/mf/project/demo/primevue-steps.\n🗃 Initializing git repository...\n⚙️ Installing CLI plugins. This might take a while...\n\n\nadded 1300 packages in 1m\n🚀 Invoking generators...\n📦 Installing additional dependencies...\n\n\nadded 71 packages in 13s\n⚓ Running completion hooks...\n\n📄 Generating README.md...\n\n🎉 Successfully created project primevue-steps.\n👉 Get started with the following commands:\n\n $ cd primevue-steps\n $ npm run serve\n\n WARN Skipped git commit due to missing username and email in git config, or failed to sign commit.\nYou will need to perform the initial commit yourself.\n```\n\n创建完成后,切换到项目目录(`例子中是 /home/mf/project/demo/primevue-steps`)\n\n```sh\ncd primevue-steps\n```\n\n\n### 2.1 安装 Vue Router\n\n由于 steps组件 是基于 Vue Router 的,所以使用前需要安装 Vue Router\n\n```sh\nnpm install vue-router@4\n```\n\n```sh\n[mf~/project/demo/primevue-steps] (master) $ npm install vue-router@4\n\nadded 2 packages, and audited 1374 packages in 18s\n\n1 package is looking for funding\n run `npm fund` for details\n\n25 vulnerabilities (11 moderate, 7 high, 7 critical)\n\nTo address issues that do not require attention, run:\n npm audit fix\n\nTo address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n```\n\n### 2.2 安装 PrimeVue \n\n```sh\nnpm install primevue@^3.15.0 --save\nnpm install primeicons --save\n```\n\n```sh\n[mf~/project/demo/primevue-steps] (master) $ npm install primevue@^3.15.0 --save\n\nadded 2 packages, and audited 1376 packages in 17s\n\n1 package is looking for funding\n run `npm fund` for details\n\n25 vulnerabilities (11 moderate, 7 high, 7 critical)\n\nTo address issues that do not require attention, run:\n npm audit fix\n\nTo address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n[mf~/project/demo/primevue-steps] (master) $ npm install primeicons --save\n\nup to date, audited 1376 packages in 9s\n\n1 package is looking for funding\n run `npm fund` for details\n\n25 vulnerabilities (11 moderate, 7 high, 7 critical)\n\nTo address issues that do not require attention, run:\n npm audit fix\n\nTo address all issues (including breaking changes), run:\n npm audit fix --force\n\nRun `npm audit` for details.\n[mf~/project/demo/primevue-steps] (master) $ \n```\n\n### 2.2 创建测试视图(view)\n\n在 `primevue-steps/src/` 目录下创建目录 `views`,用于存储视图(`primevue-steps/src/views`),在此目录下创建视图文件 `TestView.vue`\n\n```html\n<template>\n <h3>PrimeVue Steps 组件测试视图</h3>\n</template>\n\n<script>\n export default {\n name: 'TestView',\n components: {},\n setup() {\n \n }\n }\n</script>\n```\n\n### 2.3 为项目引入路由并为测试视图创建一个路由\n\n在 `primevue-steps/src/` 目录下创建目录 `router`,用于存储路由文件(`primevue-steps/src/router`),在此目录下创建路由文件 `index.js`\n\n```js\nimport { createRouter, createWebHistory } from \"vue-router\";\nimport HelloWorld from \"@/components/HelloWorld\"\nimport TestView from \"@/views/TestView\"\n\n// 两个路由,根路由(/) 和 测试视图路由(/tv)\n// 根路由和默认的示例HelloWorld组件绑定,用于显示我们的首页\n// 测试视图路由和我们的测试视图绑定,用于显示我们的测试视图\nconst routes = [\n {\n name: \"index\",\n path: \"/\",\n component: HelloWorld\n }, {\n name: \"testView\",\n path: \"/tv\",\n component: TestView\n }\n]\n\nconst router = createRouter({\n history: createWebHistory(),\n routes\n})\n\nexport default router;\n```\n\n路由文件创建完成,在 `primevue-steps/src/main.js` 文件中导入并使用路由\n\n```js\nimport { createApp } from 'vue'\nimport App from './App.vue'\n// 导入路由\nimport router from '@/router'\n// 导入PrimeVue样式\nimport 'primeicons/primeicons.css'\nimport 'primevue/resources/primevue.min.css'\nimport 'primevue/resources/themes/saga-blue/theme.css'\n\n\ncreateApp(App).use(router).mount('#app')\n```\n\n最后在 `primevue-steps/src/App.vue` 中注释掉默认内容,插入 `<router-view></router-view>` 标签,路由所对应的组件/视图都将渲染到此处\n\n```html\n<template>\n <!-- <img alt=\"Vue logo\" src=\"./assets/logo.png\">\n <HelloWorld msg=\"Welcome to Your Vue.js App\"/> -->\n <router-view></router-view>\n</template>\n\n<script>\n// import HelloWorld from './components/HelloWorld.vue'\n\nexport default {\n name: 'App',\n components: {\n // HelloWorld\n }\n}\n</script>\n\n<style>\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n</style>\n\n```\n\n启动测试服务器\n\n```sh\n[mf~/project/demo/primevue-steps] (master) $ npm run serve\n\n DONE Compiled successfully in 300ms 11:39:34 AM\n\n\n App running at:\n - Local: http://localhost:8081/ \n - Network: http://192.168.8.7:8081/\n\n\n```\n\n![](/images/post/Use-Primevue-Steps-component-vue3/1.gif)\n\n\n### 2.4 在测试视图中引入Steps组件并使用\n\n> **知识点:**\n>\n> PrimeVue中Steps组件的步骤组件切换使用嵌套路由实现,关系图如下:\n\n![](/images/post/Use-Primevue-Steps-component-vue3/2.jpg)\n\n#### 2.4.1 在测试视图中使用steps组件\n\n```html\n<template>\n <h3>PrimeVue Steps 组件测试视图</h3>\n <!-- \n sreps组件本身 \n :model=\"stepsItems\" 绑定步骤信息,每个步骤项为一个对象,指定步骤名称和要跳转的子路由地址\n :readonly=\"true\" 只读步骤,步骤条不可点击,如果为false,则可以点击相应的步骤项跳转到的子路由\n -->\n <Steps :model=\"stepsItems\" :readonly=\"true\" />\n <!-- \n 嵌套路由渲染区, 用于渲染步骤组件\n :formData=\"formObject\" 向子路由传递数据。可选,一般用于给子路由的组件传递初始值,如果不需要可以忽略\n @prevPage=\"prevPage($event)\" 监听子路由prevPage事件, 用于跳转到上一页(上一步)\n @nextPage=\"nextPage($event)\" 监听子路由nextPage事件, 用于跳转到下一页(下一步)\n @complete=\"complete\" 监听子路由complete事件,该事件触发时表示步骤完成\n -->\n <router-view \n v-slot=\"{ Component }\" \n :formData=\"formObject\" \n @prevPage=\"prevPage($event)\" \n @nextPage=\"nextPage($event)\"\n @complete=\"complete($event)\"\n >\n <keep-alive>\n <component :is=\"Component\" />\n </keep-alive>\n </router-view>\n</template>\n\n<script>\nimport { ref } from 'vue'\n// 导入router, 用于控制子路由\nimport { useRouter } from 'vue-router'\n// 导入 steps 组件\nimport Steps from 'primevue/steps'\n\nexport default {\n name: 'TestView',\n components: { Steps },\n setup() {\n // 路由实例, 控制子由跳转\n const router = useRouter()\n // 步骤条信息\n const stepsItems = ref([\n { label: '步骤1', to: '/tv/p1' },\n { label: '步骤2', to: '/tv/p2' },\n { label: '步骤3', to: '/tv/p3' },\n ])\n // 数据\n const formObject = ref({\n msg: 'Steps数据'\n })\n\n /**\n * @function 子路由事件处理函数, 跳转到下一页(下一个步骤)\n * @param {*} data 子路由组件传递的数据\n */\n const nextPage = (data) => {\n // 这里进行子路由组件数据的处理\n // 这里为了演示只是向控制台打印传递的数据\n console.info(`Steps: ${stepsItems.value[data.value.index].label}传递的数据`, data.value)\n // 跳转到下一个步骤, 下一个步骤的路由信息由stepsItems定义\n router.push(stepsItems.value[data.value.index + 1].to);\n }\n\n /**\n * @function 子路由事件处理函数, 跳转到上一页(上一个步骤)\n * @param {*} data 子路由组件传递的数据\n */\n const prevPage = (data) => {\n router.push(stepsItems.value[data.value.index - 1].to);\n };\n\n /**\n * @function 子路由事件处理函数, 步骤完成\n * @param {*} data 子路由组件传递的数据\n */\n const complete = (data) => {\n // 这里做步骤完成后的操作, 这里为了演示只是进行了简单的提示,和打印控制台\n console.info(`Steps: ${stepsItems.value[data.value.index].label}传递的数据`, data.value)\n alert('步骤完成')\n };\n\n return {\n stepsItems, formObject,\n nextPage, prevPage, complete\n }\n }\n}\n</script>\n```\n\n访问 `/tv` ,可以看到步骤条已经创建。\n\n![](/images/post/Use-Primevue-Steps-component-vue3/3.png)\n\n\n#### 2.4.2 创建子路由组件\n\n在 `primevue-steps/src/components` 目录下创建路由文件三个组件提供个`steps`组件使用\n\n- P1.vue\n- P2.vue\n- P3.vue\n\n![](/images/post/Use-Primevue-Steps-component-vue3/4.png)\n\n**P1.vue**\n\n```html\n<template>\n <div>\n <h4>步骤一:/tv/p1</h4>\n <!-- 下一页控制按钮 -->\n <button @click=\"nextPage\">下一步</button>\n </div>\n</template>\n\n<script>\nimport {ref} from 'vue'\n\nexport default {\n name: 'P1',\n components: { },\n // 声明接收steps组件传递的数据\n props: {\n formData: Object\n },\n // 声明事件\n emits: ['prevPage', 'nextPage', 'complete'],\n\n setup(props, ctx) {\n console.log('步骤一, Steps传递的数据:', props.formData)\n\n // 当前组件的数据, nextPage事件发出时传递给Steps组件\n const data = ref({\n formData: {\n msg: '我是步骤一'\n },\n index: 0\n })\n\n /**\n * @function 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页\n */\n const nextPage = () => {\n ctx.emit('nextPage', data)\n }\n\n return {\n nextPage\n }\n }\n\n \n}\n</script>\n\n<style scoped>\n div {\n width: 100%;\n height: 100px;\n border-radius: 10px;\n margin-top: 10px;\n box-shadow: 0px 0px 10px 5px #666666;\n }\n</style>\n```\n\n**P2.vue**\n\n```html\n<template>\n <div>\n <h4>步骤二:/tv/p2</h4>\n <!-- 上一页,下一页控制按钮 -->\n <button @click=\"prevPage\">上一步</button>\n <button @click=\"nextPage\">下一步</button>\n </div>\n</template>\n\n<script>\nimport {ref} from 'vue'\n\nexport default {\n name: 'P2',\n components: { },\n // 声明接收steps组件传递的数据\n props: {\n formData: Object\n },\n // 声明事件\n emits: ['prevPage', 'nextPage', 'complete'],\n\n setup(props, ctx) {\n console.log('步骤二, Steps传递的数据:', props.formData)\n\n // 当前组件的数据, nextPage事件发出时传递给Steps组件\n const data = ref({\n formData: {\n msg: '我是步骤二'\n },\n index: 1\n })\n\n /**\n * @function 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页\n */\n const nextPage = () => {\n ctx.emit('nextPage', data)\n }\n\n /**\n * @function 向steps组件发出prevPage事件,让steps组件控制router跳转到上一页\n */\n const prevPage = () => {\n ctx.emit('prevPage', data)\n }\n\n return {\n nextPage, prevPage\n }\n }\n\n \n}\n</script>\n\n<style scoped>\n div {\n width: 100%;\n height: 100px;\n border-radius: 10px;\n margin-top: 10px;\n box-shadow: 0px 0px 10px 5px #666666;\n }\n</style>\n```\n\n**P3.vue**\n\n```html\n<template>\n <div>\n <h4>步骤三:/tv/p3</h4>\n <!-- 上一页,下一页控制按钮 -->\n <button @click=\"prevPage\">上一步</button>\n <button @click=\"complete\">完成/确定</button>\n </div>\n</template>\n\n<script>\nimport {ref} from 'vue'\n\nexport default {\n name: 'P3',\n components: { },\n // 声明接收steps组件传递的数据\n props: {\n formData: Object\n },\n // 声明事件\n emits: ['prevPage', 'nextPage', 'complete'],\n\n setup(props, ctx) {\n console.log('步骤三, Steps传递的数据:', props.formData)\n\n // 当前组件的数据, nextPage事件发出时传递给Steps组件\n const data = ref({\n formData: {\n msg: '我是步骤三'\n },\n index: 2\n })\n\n /**\n * @function 向steps组件发出prevPage事件,让steps组件控制router跳转到下一页\n */\n const prevPage = () => {\n ctx.emit('prevPage', data)\n }\n\n /**\n * @function 向steps组件发出complete事件,告知steps组件步骤完成\n */\n const complete = () => {\n ctx.emit('complete', data)\n }\n\n return {\n prevPage, complete\n }\n }\n\n \n}\n</script>\n\n<style scoped>\n div {\n width: 100%;\n height: 100px;\n border-radius: 10px;\n margin-top: 10px;\n box-shadow: 0px 0px 10px 5px #666666;\n }\n</style>\n```\n\n#### 2.4.3 为子路由组件指定路由地址\n\n修改路由文件 `primevue-steps/src/router/index.js`,为TestView视图添加子路由\n\n```js\nimport { createRouter, createWebHistory } from \"vue-router\";\nimport HelloWorld from \"@/components/HelloWorld\"\nimport TestView from \"@/views/TestView\"\n// 导入子路由组件\nimport P1 from \"@/components/P1\"\nimport P2 from \"@/components/P2\"\nimport P3 from \"@/components/P3\"\n\n\nconst routes = [\n {\n name: \"index\",\n path: \"/\",\n component: HelloWorld\n }, {\n name: \"testView\",\n path: \"/tv\",\n component: TestView,\n // setps组件子路由\n children: [\n {path: 'p1', component: P1},\n {path: 'p2', component: P2},\n {path: 'p3', component: P3},\n ]\n }\n]\n\nconst router = createRouter({\n history: createWebHistory(),\n routes\n})\n\nexport default router;\n```\n\n完成后刷新页面并访问路径 `/tv/p1`,即可看到步骤页\n\n![](/images/post/Use-Primevue-Steps-component-vue3/5.gif)\n\n\n## 3. 演示Demo\n\n文章中所用的测试Demo已经推送到github:[https://github.com/mangfu26/blog-share/tree/primevue-steps](https://github.com/mangfu26/blog-share/tree/primevue-steps)\n\n你可以使用以下命令克隆使用\n\n```sh\ngit clone -b primevue-steps https://github.com/mangfu26/blog-share.git primevue-steps\n```","slug":"Use-Primevue-Steps-component-vue3","published":1,"updated":"2022-08-02T03:26:17.137Z","_id":"clb4fek6i0001z0iwb2lv12kv","comments":1,"photos":[],"link":"","content":"<h1 id=\"PrimeVue框架–Steps组件使用\"><a href=\"#PrimeVue框架–Steps组件使用\" class=\"headerlink\" title=\"PrimeVue框架–Steps组件使用\"></a>PrimeVue框架–Steps组件使用</h1><h2 id=\"1-组件简介\"><a href=\"#1-组件简介\" class=\"headerlink\" title=\"1. 组件简介\"></a>1. 组件简介</h2><blockquote>\n<p><strong>PrimeVue</strong></p>\n<p>Steps 组件是向导工作流中步骤的指示器。</p>\n<p><a href=\"https://www.primefaces.org/primevue/steps\">https://www.primefaces.org/primevue/steps</a></p>\n</blockquote>\n<p>通常称为 <code>步骤条</code>, <code>步进条</code></p>\n<p>按理来说,组件的使用直接参考官方文档即可,不需要记录到博客。</p>\n<p>但是 PrimeVue 的步骤条与 Element 框架点区别,PrimeVue 的步骤条是基于 Vue Router 的,之前没有接触过,使用过程中踩了一两个坑,所以还是打算用博客的形式记录一下使用方法,供日后参考,而不是苦哈哈的再去研究官方文档💀</p>\n<h2 id=\"2-使用方法\"><a href=\"#2-使用方法\" class=\"headerlink\" title=\"2. 使用方法\"></a>2. 使用方法</h2><blockquote>\n<p><strong>小提示</strong>:</p>\n<p>所有代码都基于Vue3项目,所以确保您拥有一个vue3项目</p>\n<p>如果您没有,请使用 <a href=\"https://cli.vuejs.org/zh/\">Vue-CLI</a> 创建,参考:<a href=\"https://cli.vuejs.org/zh/guide/creating-a-project.html\">https://cli.vuejs.org/zh/guide/creating-a-project.html</a></p>\n</blockquote>\n<p><strong>创建一个Vue3项目</strong></p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo] $ vue create primevue-steps<br></code></pre></td></tr></table></figure>\n\n<p><strong>选择Vue3选项</strong></p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">Vue CLI v4.5.15<br>┌──────────────────────────────────────────┐<br>│ │<br>│ New version available 4.5.15 → 5.0.8 │<br>│ Run npm i -g @vue/cli to update! │<br>│ │<br>└──────────────────────────────────────────┘<br><br>? Please pick a preset: <br> Default ([Vue 2] babel, eslint) <br>❯ Default (Vue 3) ([Vue 3] babel, eslint) <br> Manually select features <br></code></pre></td></tr></table></figure>\n\n<p><strong>等待创建完成</strong></p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">Vue CLI v4.5.15<br>✨ Creating project <span class=\"hljs-keyword\">in</span> /home/mf/project/demo/primevue-steps.<br>🗃 Initializing git repository...<br>⚙️ Installing CLI plugins. This might take a <span class=\"hljs-keyword\">while</span>...<br><br><br>added 1300 packages <span class=\"hljs-keyword\">in</span> 1m<br>🚀 Invoking generators...<br>📦 Installing additional dependencies...<br><br><br>added 71 packages <span class=\"hljs-keyword\">in</span> 13s<br>⚓ Running completion hooks...<br><br>📄 Generating README.md...<br><br>🎉 Successfully created project primevue-steps.<br>👉 Get started with the following commands:<br><br> $ <span class=\"hljs-built_in\">cd</span> primevue-steps<br> $ npm run serve<br><br> WARN Skipped git commit due to missing username and email <span class=\"hljs-keyword\">in</span> git config, or failed to sign commit.<br>You will need to perform the initial commit yourself.<br></code></pre></td></tr></table></figure>\n\n<p>创建完成后,切换到项目目录(<code>例子中是 /home/mf/project/demo/primevue-steps</code>)</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\"><span class=\"hljs-built_in\">cd</span> primevue-steps<br></code></pre></td></tr></table></figure>\n\n\n<h3 id=\"2-1-安装-Vue-Router\"><a href=\"#2-1-安装-Vue-Router\" class=\"headerlink\" title=\"2.1 安装 Vue Router\"></a>2.1 安装 Vue Router</h3><p>由于 steps组件 是基于 Vue Router 的,所以使用前需要安装 Vue Router</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">npm install vue-router@4<br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo/primevue-steps] (master) $ npm install vue-router@4<br><br>added 2 packages, and audited 1374 packages <span class=\"hljs-keyword\">in</span> 18s<br><br>1 package is looking <span class=\"hljs-keyword\">for</span> funding<br> run `npm fund` <span class=\"hljs-keyword\">for</span> details<br><br>25 vulnerabilities (11 moderate, 7 high, 7 critical)<br><br>To address issues that <span class=\"hljs-keyword\">do</span> not require attention, run:<br> npm audit fix<br><br>To address all issues (including breaking changes), run:<br> npm audit fix --force<br><br>Run `npm audit` <span class=\"hljs-keyword\">for</span> details.<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-2-安装-PrimeVue\"><a href=\"#2-2-安装-PrimeVue\" class=\"headerlink\" title=\"2.2 安装 PrimeVue\"></a>2.2 安装 PrimeVue</h3><figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">npm install primevue@^3.15.0 --save<br>npm install primeicons --save<br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo/primevue-steps] (master) $ npm install primevue@^3.15.0 --save<br><br>added 2 packages, and audited 1376 packages <span class=\"hljs-keyword\">in</span> 17s<br><br>1 package is looking <span class=\"hljs-keyword\">for</span> funding<br> run `npm fund` <span class=\"hljs-keyword\">for</span> details<br><br>25 vulnerabilities (11 moderate, 7 high, 7 critical)<br><br>To address issues that <span class=\"hljs-keyword\">do</span> not require attention, run:<br> npm audit fix<br><br>To address all issues (including breaking changes), run:<br> npm audit fix --force<br><br>Run `npm audit` <span class=\"hljs-keyword\">for</span> details.<br>[mf~/project/demo/primevue-steps] (master) $ npm install primeicons --save<br><br>up to <span class=\"hljs-built_in\">date</span>, audited 1376 packages <span class=\"hljs-keyword\">in</span> 9s<br><br>1 package is looking <span class=\"hljs-keyword\">for</span> funding<br> run `npm fund` <span class=\"hljs-keyword\">for</span> details<br><br>25 vulnerabilities (11 moderate, 7 high, 7 critical)<br><br>To address issues that <span class=\"hljs-keyword\">do</span> not require attention, run:<br> npm audit fix<br><br>To address all issues (including breaking changes), run:<br> npm audit fix --force<br><br>Run `npm audit` <span class=\"hljs-keyword\">for</span> details.<br>[mf~/project/demo/primevue-steps] (master) $ <br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-2-创建测试视图-view\"><a href=\"#2-2-创建测试视图-view\" class=\"headerlink\" title=\"2.2 创建测试视图(view)\"></a>2.2 创建测试视图(view)</h3><p>在 <code>primevue-steps/src/</code> 目录下创建目录 <code>views</code>,用于存储视图(<code>primevue-steps/src/views</code>),在此目录下创建视图文件 <code>TestView.vue</code></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h3</span>></span>PrimeVue Steps 组件测试视图<span class=\"hljs-tag\"></<span class=\"hljs-name\">h3</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'TestView'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: {},</span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\"></span>) {</span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-3-为项目引入路由并为测试视图创建一个路由\"><a href=\"#2-3-为项目引入路由并为测试视图创建一个路由\" class=\"headerlink\" title=\"2.3 为项目引入路由并为测试视图创建一个路由\"></a>2.3 为项目引入路由并为测试视图创建一个路由</h3><p>在 <code>primevue-steps/src/</code> 目录下创建目录 <code>router</code>,用于存储路由文件(<code>primevue-steps/src/router</code>),在此目录下创建路由文件 <code>index.js</code></p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs js\"><span class=\"hljs-keyword\">import</span> { createRouter, createWebHistory } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"vue-router"</span>;<br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">HelloWorld</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/HelloWorld"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">TestView</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/views/TestView"</span><br><br><span class=\"hljs-comment\">// 两个路由,根路由(/) 和 测试视图路由(/tv)</span><br><span class=\"hljs-comment\">// 根路由和默认的示例HelloWorld组件绑定,用于显示我们的首页</span><br><span class=\"hljs-comment\">// 测试视图路由和我们的测试视图绑定,用于显示我们的测试视图</span><br><span class=\"hljs-keyword\">const</span> routes = [<br> {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"index"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">HelloWorld</span><br> }, {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"testView"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/tv"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">TestView</span><br> }<br>]<br><br><span class=\"hljs-keyword\">const</span> router = <span class=\"hljs-title function_\">createRouter</span>({<br> <span class=\"hljs-attr\">history</span>: <span class=\"hljs-title function_\">createWebHistory</span>(),<br> routes<br>})<br><br><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> router;<br></code></pre></td></tr></table></figure>\n\n<p>路由文件创建完成,在 <code>primevue-steps/src/main.js</code> 文件中导入并使用路由</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs js\"><span class=\"hljs-keyword\">import</span> { createApp } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">App</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'./App.vue'</span><br><span class=\"hljs-comment\">// 导入路由</span><br><span class=\"hljs-keyword\">import</span> router <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'@/router'</span><br><span class=\"hljs-comment\">// 导入PrimeVue样式</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-string\">'primeicons/primeicons.css'</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-string\">'primevue/resources/primevue.min.css'</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-string\">'primevue/resources/themes/saga-blue/theme.css'</span><br><br><br><span class=\"hljs-title function_\">createApp</span>(<span class=\"hljs-title class_\">App</span>).<span class=\"hljs-title function_\">use</span>(router).<span class=\"hljs-title function_\">mount</span>(<span class=\"hljs-string\">'#app'</span>)<br></code></pre></td></tr></table></figure>\n\n<p>最后在 <code>primevue-steps/src/App.vue</code> 中注释掉默认内容,插入 <code><router-view></router-view></code> 标签,路由所对应的组件/视图都将渲染到此处</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-comment\"><!-- <img alt="Vue logo" src="./assets/logo.png"></span><br><span class=\"hljs-comment\"> <HelloWorld msg="Welcome to Your Vue.js App"/> --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">router-view</span>></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">router-view</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-comment\">// import HelloWorld from './components/HelloWorld.vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'App'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// HelloWorld</span></span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"><span class=\"hljs-selector-id\">#app</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">font-family</span>: Avenir, Helvetica, Arial, sans-serif;</span><br><span class=\"language-css\"> -webkit-<span class=\"hljs-attribute\">font-smoothing</span>: antialiased;</span><br><span class=\"language-css\"> -moz-osx-<span class=\"hljs-attribute\">font-smoothing</span>: grayscale;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">text-align</span>: center;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">color</span>: <span class=\"hljs-number\">#2c3e50</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">60px</span>;</span><br><span class=\"language-css\">}</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br><br></code></pre></td></tr></table></figure>\n\n<p>启动测试服务器</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo/primevue-steps] (master) $ npm run serve<br><br> DONE Compiled successfully <span class=\"hljs-keyword\">in</span> 300ms 11:39:34 AM<br><br><br> App running at:<br> - Local: http://localhost:8081/ <br> - Network: http://192.168.8.7:8081/<br><br><br></code></pre></td></tr></table></figure>\n\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/1.gif\"></p>\n<h3 id=\"2-4-在测试视图中引入Steps组件并使用\"><a href=\"#2-4-在测试视图中引入Steps组件并使用\" class=\"headerlink\" title=\"2.4 在测试视图中引入Steps组件并使用\"></a>2.4 在测试视图中引入Steps组件并使用</h3><blockquote>\n<p><strong>知识点:</strong></p>\n<p>PrimeVue中Steps组件的步骤组件切换使用嵌套路由实现,关系图如下:</p>\n</blockquote>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/2.jpg\"></p>\n<h4 id=\"2-4-1-在测试视图中使用steps组件\"><a href=\"#2-4-1-在测试视图中使用steps组件\" class=\"headerlink\" title=\"2.4.1 在测试视图中使用steps组件\"></a>2.4.1 在测试视图中使用steps组件</h4><figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h3</span>></span>PrimeVue Steps 组件测试视图<span class=\"hljs-tag\"></<span class=\"hljs-name\">h3</span>></span><br> <span class=\"hljs-comment\"><!-- </span><br><span class=\"hljs-comment\"> sreps组件本身 </span><br><span class=\"hljs-comment\"> :model="stepsItems" 绑定步骤信息,每个步骤项为一个对象,指定步骤名称和要跳转的子路由地址</span><br><span class=\"hljs-comment\"> :readonly="true" 只读步骤,步骤条不可点击,如果为false,则可以点击相应的步骤项跳转到的子路由</span><br><span class=\"hljs-comment\"> --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">Steps</span> <span class=\"hljs-attr\">:model</span>=<span class=\"hljs-string\">"stepsItems"</span> <span class=\"hljs-attr\">:readonly</span>=<span class=\"hljs-string\">"true"</span> /></span><br> <span class=\"hljs-comment\"><!-- </span><br><span class=\"hljs-comment\"> 嵌套路由渲染区, 用于渲染步骤组件</span><br><span class=\"hljs-comment\"> :formData="formObject" 向子路由传递数据。可选,一般用于给子路由的组件传递初始值,如果不需要可以忽略</span><br><span class=\"hljs-comment\"> @prevPage="prevPage($event)" 监听子路由prevPage事件, 用于跳转到上一页(上一步)</span><br><span class=\"hljs-comment\"> @nextPage="nextPage($event)" 监听子路由nextPage事件, 用于跳转到下一页(下一步)</span><br><span class=\"hljs-comment\"> @complete="complete" 监听子路由complete事件,该事件触发时表示步骤完成</span><br><span class=\"hljs-comment\"> --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">router-view</span> </span><br><span class=\"hljs-tag\"> <span class=\"hljs-attr\">v-slot</span>=<span class=\"hljs-string\">"{ Component }"</span> </span><br><span class=\"hljs-tag\"> <span class=\"hljs-attr\">:formData</span>=<span class=\"hljs-string\">"formObject"</span> </span><br><span class=\"hljs-tag\"> @<span class=\"hljs-attr\">prevPage</span>=<span class=\"hljs-string\">"prevPage($event)"</span> </span><br><span class=\"hljs-tag\"> @<span class=\"hljs-attr\">nextPage</span>=<span class=\"hljs-string\">"nextPage($event)"</span></span><br><span class=\"hljs-tag\"> @<span class=\"hljs-attr\">complete</span>=<span class=\"hljs-string\">"complete($event)"</span></span><br><span class=\"hljs-tag\"> ></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">keep-alive</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">component</span> <span class=\"hljs-attr\">:is</span>=<span class=\"hljs-string\">"Component"</span> /></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">keep-alive</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">router-view</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> { ref } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"><span class=\"hljs-comment\">// 导入router, 用于控制子路由</span></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> { useRouter } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue-router'</span></span><br><span class=\"language-javascript\"><span class=\"hljs-comment\">// 导入 steps 组件</span></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">Steps</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'primevue/steps'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'TestView'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { <span class=\"hljs-title class_\">Steps</span> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\"></span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 路由实例, 控制子由跳转</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> router = <span class=\"hljs-title function_\">useRouter</span>()</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 步骤条信息</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> stepsItems = <span class=\"hljs-title function_\">ref</span>([</span><br><span class=\"language-javascript\"> { <span class=\"hljs-attr\">label</span>: <span class=\"hljs-string\">'步骤1'</span>, <span class=\"hljs-attr\">to</span>: <span class=\"hljs-string\">'/tv/p1'</span> },</span><br><span class=\"language-javascript\"> { <span class=\"hljs-attr\">label</span>: <span class=\"hljs-string\">'步骤2'</span>, <span class=\"hljs-attr\">to</span>: <span class=\"hljs-string\">'/tv/p2'</span> },</span><br><span class=\"language-javascript\"> { <span class=\"hljs-attr\">label</span>: <span class=\"hljs-string\">'步骤3'</span>, <span class=\"hljs-attr\">to</span>: <span class=\"hljs-string\">'/tv/p3'</span> },</span><br><span class=\"language-javascript\"> ])</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> formObject = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'Steps数据'</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 子路由事件处理函数, 跳转到下一页(下一个步骤)</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@param</span> {<span class=\"hljs-type\">*</span>} data 子路由组件传递的数据</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">nextPage</span> = (<span class=\"hljs-params\">data</span>) => {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 这里进行子路由组件数据的处理</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 这里为了演示只是向控制台打印传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">info</span>(<span class=\"hljs-string\">`Steps: <span class=\"hljs-subst\">${stepsItems.value[data.value.index].label}</span>传递的数据`</span>, data.<span class=\"hljs-property\">value</span>)</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 跳转到下一个步骤, 下一个步骤的路由信息由stepsItems定义</span></span><br><span class=\"language-javascript\"> router.<span class=\"hljs-title function_\">push</span>(stepsItems.<span class=\"hljs-property\">value</span>[data.<span class=\"hljs-property\">value</span>.<span class=\"hljs-property\">index</span> + <span class=\"hljs-number\">1</span>].<span class=\"hljs-property\">to</span>);</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 子路由事件处理函数, 跳转到上一页(上一个步骤)</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@param</span> {<span class=\"hljs-type\">*</span>} data 子路由组件传递的数据</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">prevPage</span> = (<span class=\"hljs-params\">data</span>) => {</span><br><span class=\"language-javascript\"> router.<span class=\"hljs-title function_\">push</span>(stepsItems.<span class=\"hljs-property\">value</span>[data.<span class=\"hljs-property\">value</span>.<span class=\"hljs-property\">index</span> - <span class=\"hljs-number\">1</span>].<span class=\"hljs-property\">to</span>);</span><br><span class=\"language-javascript\"> };</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 子路由事件处理函数, 步骤完成</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@param</span> {<span class=\"hljs-type\">*</span>} data 子路由组件传递的数据</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">complete</span> = (<span class=\"hljs-params\">data</span>) => {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 这里做步骤完成后的操作, 这里为了演示只是进行了简单的提示,和打印控制台</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">info</span>(<span class=\"hljs-string\">`Steps: <span class=\"hljs-subst\">${stepsItems.value[data.value.index].label}</span>传递的数据`</span>, data.<span class=\"hljs-property\">value</span>)</span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">alert</span>(<span class=\"hljs-string\">'步骤完成'</span>)</span><br><span class=\"language-javascript\"> };</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> stepsItems, formObject,</span><br><span class=\"language-javascript\"> nextPage, prevPage, complete</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br></code></pre></td></tr></table></figure>\n\n<p>访问 <code>/tv</code> ,可以看到步骤条已经创建。</p>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/3.png\"></p>\n<h4 id=\"2-4-2-创建子路由组件\"><a href=\"#2-4-2-创建子路由组件\" class=\"headerlink\" title=\"2.4.2 创建子路由组件\"></a>2.4.2 创建子路由组件</h4><p>在 <code>primevue-steps/src/components</code> 目录下创建路由文件三个组件提供个<code>steps</code>组件使用</p>\n<ul>\n<li>P1.vue</li>\n<li>P2.vue</li>\n<li>P3.vue</li>\n</ul>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/4.png\"></p>\n<p><strong>P1.vue</strong></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>步骤一:/tv/p1<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span><br> <span class=\"hljs-comment\"><!-- 下一页控制按钮 --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"nextPage"</span>></span>下一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> {ref} <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'P1'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明接收steps组件传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">props</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: <span class=\"hljs-title class_\">Object</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明事件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">emits</span>: [<span class=\"hljs-string\">'prevPage'</span>, <span class=\"hljs-string\">'nextPage'</span>, <span class=\"hljs-string\">'complete'</span>],</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\">props, ctx</span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">log</span>(<span class=\"hljs-string\">'步骤一, Steps传递的数据:'</span>, props.<span class=\"hljs-property\">formData</span>)</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 当前组件的数据, nextPage事件发出时传递给Steps组件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> data = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'我是步骤一'</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">index</span>: <span class=\"hljs-number\">0</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">nextPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'nextPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> nextPage</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span> <span class=\"hljs-attr\">scoped</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"> <span class=\"hljs-selector-tag\">div</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">width</span>: <span class=\"hljs-number\">100%</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">height</span>: <span class=\"hljs-number\">100px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">border-radius</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">box-shadow</span>: <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">10px</span> <span class=\"hljs-number\">5px</span> <span class=\"hljs-number\">#666666</span>;</span><br><span class=\"language-css\"> }</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br></code></pre></td></tr></table></figure>\n\n<p><strong>P2.vue</strong></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>步骤二:/tv/p2<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span><br> <span class=\"hljs-comment\"><!-- 上一页,下一页控制按钮 --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"prevPage"</span>></span>上一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"nextPage"</span>></span>下一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> {ref} <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'P2'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明接收steps组件传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">props</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: <span class=\"hljs-title class_\">Object</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明事件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">emits</span>: [<span class=\"hljs-string\">'prevPage'</span>, <span class=\"hljs-string\">'nextPage'</span>, <span class=\"hljs-string\">'complete'</span>],</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\">props, ctx</span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">log</span>(<span class=\"hljs-string\">'步骤二, Steps传递的数据:'</span>, props.<span class=\"hljs-property\">formData</span>)</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 当前组件的数据, nextPage事件发出时传递给Steps组件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> data = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'我是步骤二'</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">index</span>: <span class=\"hljs-number\">1</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">nextPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'nextPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出prevPage事件,让steps组件控制router跳转到上一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">prevPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'prevPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> nextPage, prevPage</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span> <span class=\"hljs-attr\">scoped</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"> <span class=\"hljs-selector-tag\">div</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">width</span>: <span class=\"hljs-number\">100%</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">height</span>: <span class=\"hljs-number\">100px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">border-radius</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">box-shadow</span>: <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">10px</span> <span class=\"hljs-number\">5px</span> <span class=\"hljs-number\">#666666</span>;</span><br><span class=\"language-css\"> }</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br></code></pre></td></tr></table></figure>\n\n<p><strong>P3.vue</strong></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>步骤三:/tv/p3<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span><br> <span class=\"hljs-comment\"><!-- 上一页,下一页控制按钮 --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"prevPage"</span>></span>上一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"complete"</span>></span>完成/确定<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> {ref} <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'P3'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明接收steps组件传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">props</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: <span class=\"hljs-title class_\">Object</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明事件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">emits</span>: [<span class=\"hljs-string\">'prevPage'</span>, <span class=\"hljs-string\">'nextPage'</span>, <span class=\"hljs-string\">'complete'</span>],</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\">props, ctx</span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">log</span>(<span class=\"hljs-string\">'步骤三, Steps传递的数据:'</span>, props.<span class=\"hljs-property\">formData</span>)</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 当前组件的数据, nextPage事件发出时传递给Steps组件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> data = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'我是步骤三'</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">index</span>: <span class=\"hljs-number\">2</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出prevPage事件,让steps组件控制router跳转到下一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">prevPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'prevPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出complete事件,告知steps组件步骤完成</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">complete</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'complete'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> prevPage, complete</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span> <span class=\"hljs-attr\">scoped</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"> <span class=\"hljs-selector-tag\">div</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">width</span>: <span class=\"hljs-number\">100%</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">height</span>: <span class=\"hljs-number\">100px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">border-radius</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">box-shadow</span>: <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">10px</span> <span class=\"hljs-number\">5px</span> <span class=\"hljs-number\">#666666</span>;</span><br><span class=\"language-css\"> }</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br></code></pre></td></tr></table></figure>\n\n<h4 id=\"2-4-3-为子路由组件指定路由地址\"><a href=\"#2-4-3-为子路由组件指定路由地址\" class=\"headerlink\" title=\"2.4.3 为子路由组件指定路由地址\"></a>2.4.3 为子路由组件指定路由地址</h4><p>修改路由文件 <code>primevue-steps/src/router/index.js</code>,为TestView视图添加子路由</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs js\"><span class=\"hljs-keyword\">import</span> { createRouter, createWebHistory } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"vue-router"</span>;<br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">HelloWorld</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/HelloWorld"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">TestView</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/views/TestView"</span><br><span class=\"hljs-comment\">// 导入子路由组件</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-variable constant_\">P1</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/P1"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-variable constant_\">P2</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/P2"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-variable constant_\">P3</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/P3"</span><br><br><br><span class=\"hljs-keyword\">const</span> routes = [<br> {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"index"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">HelloWorld</span><br> }, {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"testView"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/tv"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">TestView</span>,<br> <span class=\"hljs-comment\">// setps组件子路由</span><br> <span class=\"hljs-attr\">children</span>: [<br> {<span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">'p1'</span>, <span class=\"hljs-attr\">component</span>: <span class=\"hljs-variable constant_\">P1</span>},<br> {<span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">'p2'</span>, <span class=\"hljs-attr\">component</span>: <span class=\"hljs-variable constant_\">P2</span>},<br> {<span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">'p3'</span>, <span class=\"hljs-attr\">component</span>: <span class=\"hljs-variable constant_\">P3</span>},<br> ]<br> }<br>]<br><br><span class=\"hljs-keyword\">const</span> router = <span class=\"hljs-title function_\">createRouter</span>({<br> <span class=\"hljs-attr\">history</span>: <span class=\"hljs-title function_\">createWebHistory</span>(),<br> routes<br>})<br><br><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> router;<br></code></pre></td></tr></table></figure>\n\n<p>完成后刷新页面并访问路径 <code>/tv/p1</code>,即可看到步骤页</p>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/5.gif\"></p>\n<h2 id=\"3-演示Demo\"><a href=\"#3-演示Demo\" class=\"headerlink\" title=\"3. 演示Demo\"></a>3. 演示Demo</h2><p>文章中所用的测试Demo已经推送到github:<a href=\"https://github.com/mangfu26/blog-share/tree/primevue-steps\">https://github.com/mangfu26/blog-share/tree/primevue-steps</a></p>\n<p>你可以使用以下命令克隆使用</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">git <span class=\"hljs-built_in\">clone</span> -b primevue-steps https://github.com/mangfu26/blog-share.git primevue-steps<br></code></pre></td></tr></table></figure>","site":{"data":{}},"wordcount":12195,"excerpt":"","more":"<h1 id=\"PrimeVue框架–Steps组件使用\"><a href=\"#PrimeVue框架–Steps组件使用\" class=\"headerlink\" title=\"PrimeVue框架–Steps组件使用\"></a>PrimeVue框架–Steps组件使用</h1><h2 id=\"1-组件简介\"><a href=\"#1-组件简介\" class=\"headerlink\" title=\"1. 组件简介\"></a>1. 组件简介</h2><blockquote>\n<p><strong>PrimeVue</strong></p>\n<p>Steps 组件是向导工作流中步骤的指示器。</p>\n<p><a href=\"https://www.primefaces.org/primevue/steps\">https://www.primefaces.org/primevue/steps</a></p>\n</blockquote>\n<p>通常称为 <code>步骤条</code>, <code>步进条</code></p>\n<p>按理来说,组件的使用直接参考官方文档即可,不需要记录到博客。</p>\n<p>但是 PrimeVue 的步骤条与 Element 框架点区别,PrimeVue 的步骤条是基于 Vue Router 的,之前没有接触过,使用过程中踩了一两个坑,所以还是打算用博客的形式记录一下使用方法,供日后参考,而不是苦哈哈的再去研究官方文档💀</p>\n<h2 id=\"2-使用方法\"><a href=\"#2-使用方法\" class=\"headerlink\" title=\"2. 使用方法\"></a>2. 使用方法</h2><blockquote>\n<p><strong>小提示</strong>:</p>\n<p>所有代码都基于Vue3项目,所以确保您拥有一个vue3项目</p>\n<p>如果您没有,请使用 <a href=\"https://cli.vuejs.org/zh/\">Vue-CLI</a> 创建,参考:<a href=\"https://cli.vuejs.org/zh/guide/creating-a-project.html\">https://cli.vuejs.org/zh/guide/creating-a-project.html</a></p>\n</blockquote>\n<p><strong>创建一个Vue3项目</strong></p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo] $ vue create primevue-steps<br></code></pre></td></tr></table></figure>\n\n<p><strong>选择Vue3选项</strong></p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">Vue CLI v4.5.15<br>┌──────────────────────────────────────────┐<br>│ │<br>│ New version available 4.5.15 → 5.0.8 │<br>│ Run npm i -g @vue/cli to update! │<br>│ │<br>└──────────────────────────────────────────┘<br><br>? Please pick a preset: <br> Default ([Vue 2] babel, eslint) <br>❯ Default (Vue 3) ([Vue 3] babel, eslint) <br> Manually select features <br></code></pre></td></tr></table></figure>\n\n<p><strong>等待创建完成</strong></p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">Vue CLI v4.5.15<br>✨ Creating project <span class=\"hljs-keyword\">in</span> /home/mf/project/demo/primevue-steps.<br>🗃 Initializing git repository...<br>⚙️ Installing CLI plugins. This might take a <span class=\"hljs-keyword\">while</span>...<br><br><br>added 1300 packages <span class=\"hljs-keyword\">in</span> 1m<br>🚀 Invoking generators...<br>📦 Installing additional dependencies...<br><br><br>added 71 packages <span class=\"hljs-keyword\">in</span> 13s<br>⚓ Running completion hooks...<br><br>📄 Generating README.md...<br><br>🎉 Successfully created project primevue-steps.<br>👉 Get started with the following commands:<br><br> $ <span class=\"hljs-built_in\">cd</span> primevue-steps<br> $ npm run serve<br><br> WARN Skipped git commit due to missing username and email <span class=\"hljs-keyword\">in</span> git config, or failed to sign commit.<br>You will need to perform the initial commit yourself.<br></code></pre></td></tr></table></figure>\n\n<p>创建完成后,切换到项目目录(<code>例子中是 /home/mf/project/demo/primevue-steps</code>)</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\"><span class=\"hljs-built_in\">cd</span> primevue-steps<br></code></pre></td></tr></table></figure>\n\n\n<h3 id=\"2-1-安装-Vue-Router\"><a href=\"#2-1-安装-Vue-Router\" class=\"headerlink\" title=\"2.1 安装 Vue Router\"></a>2.1 安装 Vue Router</h3><p>由于 steps组件 是基于 Vue Router 的,所以使用前需要安装 Vue Router</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">npm install vue-router@4<br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo/primevue-steps] (master) $ npm install vue-router@4<br><br>added 2 packages, and audited 1374 packages <span class=\"hljs-keyword\">in</span> 18s<br><br>1 package is looking <span class=\"hljs-keyword\">for</span> funding<br> run `npm fund` <span class=\"hljs-keyword\">for</span> details<br><br>25 vulnerabilities (11 moderate, 7 high, 7 critical)<br><br>To address issues that <span class=\"hljs-keyword\">do</span> not require attention, run:<br> npm audit fix<br><br>To address all issues (including breaking changes), run:<br> npm audit fix --force<br><br>Run `npm audit` <span class=\"hljs-keyword\">for</span> details.<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-2-安装-PrimeVue\"><a href=\"#2-2-安装-PrimeVue\" class=\"headerlink\" title=\"2.2 安装 PrimeVue\"></a>2.2 安装 PrimeVue</h3><figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">npm install primevue@^3.15.0 --save<br>npm install primeicons --save<br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo/primevue-steps] (master) $ npm install primevue@^3.15.0 --save<br><br>added 2 packages, and audited 1376 packages <span class=\"hljs-keyword\">in</span> 17s<br><br>1 package is looking <span class=\"hljs-keyword\">for</span> funding<br> run `npm fund` <span class=\"hljs-keyword\">for</span> details<br><br>25 vulnerabilities (11 moderate, 7 high, 7 critical)<br><br>To address issues that <span class=\"hljs-keyword\">do</span> not require attention, run:<br> npm audit fix<br><br>To address all issues (including breaking changes), run:<br> npm audit fix --force<br><br>Run `npm audit` <span class=\"hljs-keyword\">for</span> details.<br>[mf~/project/demo/primevue-steps] (master) $ npm install primeicons --save<br><br>up to <span class=\"hljs-built_in\">date</span>, audited 1376 packages <span class=\"hljs-keyword\">in</span> 9s<br><br>1 package is looking <span class=\"hljs-keyword\">for</span> funding<br> run `npm fund` <span class=\"hljs-keyword\">for</span> details<br><br>25 vulnerabilities (11 moderate, 7 high, 7 critical)<br><br>To address issues that <span class=\"hljs-keyword\">do</span> not require attention, run:<br> npm audit fix<br><br>To address all issues (including breaking changes), run:<br> npm audit fix --force<br><br>Run `npm audit` <span class=\"hljs-keyword\">for</span> details.<br>[mf~/project/demo/primevue-steps] (master) $ <br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-2-创建测试视图-view\"><a href=\"#2-2-创建测试视图-view\" class=\"headerlink\" title=\"2.2 创建测试视图(view)\"></a>2.2 创建测试视图(view)</h3><p>在 <code>primevue-steps/src/</code> 目录下创建目录 <code>views</code>,用于存储视图(<code>primevue-steps/src/views</code>),在此目录下创建视图文件 <code>TestView.vue</code></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h3</span>></span>PrimeVue Steps 组件测试视图<span class=\"hljs-tag\"></<span class=\"hljs-name\">h3</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'TestView'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: {},</span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\"></span>) {</span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-3-为项目引入路由并为测试视图创建一个路由\"><a href=\"#2-3-为项目引入路由并为测试视图创建一个路由\" class=\"headerlink\" title=\"2.3 为项目引入路由并为测试视图创建一个路由\"></a>2.3 为项目引入路由并为测试视图创建一个路由</h3><p>在 <code>primevue-steps/src/</code> 目录下创建目录 <code>router</code>,用于存储路由文件(<code>primevue-steps/src/router</code>),在此目录下创建路由文件 <code>index.js</code></p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs js\"><span class=\"hljs-keyword\">import</span> { createRouter, createWebHistory } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"vue-router"</span>;<br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">HelloWorld</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/HelloWorld"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">TestView</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/views/TestView"</span><br><br><span class=\"hljs-comment\">// 两个路由,根路由(/) 和 测试视图路由(/tv)</span><br><span class=\"hljs-comment\">// 根路由和默认的示例HelloWorld组件绑定,用于显示我们的首页</span><br><span class=\"hljs-comment\">// 测试视图路由和我们的测试视图绑定,用于显示我们的测试视图</span><br><span class=\"hljs-keyword\">const</span> routes = [<br> {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"index"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">HelloWorld</span><br> }, {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"testView"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/tv"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">TestView</span><br> }<br>]<br><br><span class=\"hljs-keyword\">const</span> router = <span class=\"hljs-title function_\">createRouter</span>({<br> <span class=\"hljs-attr\">history</span>: <span class=\"hljs-title function_\">createWebHistory</span>(),<br> routes<br>})<br><br><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> router;<br></code></pre></td></tr></table></figure>\n\n<p>路由文件创建完成,在 <code>primevue-steps/src/main.js</code> 文件中导入并使用路由</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs js\"><span class=\"hljs-keyword\">import</span> { createApp } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">App</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'./App.vue'</span><br><span class=\"hljs-comment\">// 导入路由</span><br><span class=\"hljs-keyword\">import</span> router <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'@/router'</span><br><span class=\"hljs-comment\">// 导入PrimeVue样式</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-string\">'primeicons/primeicons.css'</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-string\">'primevue/resources/primevue.min.css'</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-string\">'primevue/resources/themes/saga-blue/theme.css'</span><br><br><br><span class=\"hljs-title function_\">createApp</span>(<span class=\"hljs-title class_\">App</span>).<span class=\"hljs-title function_\">use</span>(router).<span class=\"hljs-title function_\">mount</span>(<span class=\"hljs-string\">'#app'</span>)<br></code></pre></td></tr></table></figure>\n\n<p>最后在 <code>primevue-steps/src/App.vue</code> 中注释掉默认内容,插入 <code><router-view></router-view></code> 标签,路由所对应的组件/视图都将渲染到此处</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-comment\"><!-- <img alt="Vue logo" src="./assets/logo.png"></span><br><span class=\"hljs-comment\"> <HelloWorld msg="Welcome to Your Vue.js App"/> --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">router-view</span>></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">router-view</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-comment\">// import HelloWorld from './components/HelloWorld.vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'App'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// HelloWorld</span></span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"><span class=\"hljs-selector-id\">#app</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">font-family</span>: Avenir, Helvetica, Arial, sans-serif;</span><br><span class=\"language-css\"> -webkit-<span class=\"hljs-attribute\">font-smoothing</span>: antialiased;</span><br><span class=\"language-css\"> -moz-osx-<span class=\"hljs-attribute\">font-smoothing</span>: grayscale;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">text-align</span>: center;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">color</span>: <span class=\"hljs-number\">#2c3e50</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">60px</span>;</span><br><span class=\"language-css\">}</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br><br></code></pre></td></tr></table></figure>\n\n<p>启动测试服务器</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">[mf~/project/demo/primevue-steps] (master) $ npm run serve<br><br> DONE Compiled successfully <span class=\"hljs-keyword\">in</span> 300ms 11:39:34 AM<br><br><br> App running at:<br> - Local: http://localhost:8081/ <br> - Network: http://192.168.8.7:8081/<br><br><br></code></pre></td></tr></table></figure>\n\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/1.gif\"></p>\n<h3 id=\"2-4-在测试视图中引入Steps组件并使用\"><a href=\"#2-4-在测试视图中引入Steps组件并使用\" class=\"headerlink\" title=\"2.4 在测试视图中引入Steps组件并使用\"></a>2.4 在测试视图中引入Steps组件并使用</h3><blockquote>\n<p><strong>知识点:</strong></p>\n<p>PrimeVue中Steps组件的步骤组件切换使用嵌套路由实现,关系图如下:</p>\n</blockquote>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/2.jpg\"></p>\n<h4 id=\"2-4-1-在测试视图中使用steps组件\"><a href=\"#2-4-1-在测试视图中使用steps组件\" class=\"headerlink\" title=\"2.4.1 在测试视图中使用steps组件\"></a>2.4.1 在测试视图中使用steps组件</h4><figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h3</span>></span>PrimeVue Steps 组件测试视图<span class=\"hljs-tag\"></<span class=\"hljs-name\">h3</span>></span><br> <span class=\"hljs-comment\"><!-- </span><br><span class=\"hljs-comment\"> sreps组件本身 </span><br><span class=\"hljs-comment\"> :model="stepsItems" 绑定步骤信息,每个步骤项为一个对象,指定步骤名称和要跳转的子路由地址</span><br><span class=\"hljs-comment\"> :readonly="true" 只读步骤,步骤条不可点击,如果为false,则可以点击相应的步骤项跳转到的子路由</span><br><span class=\"hljs-comment\"> --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">Steps</span> <span class=\"hljs-attr\">:model</span>=<span class=\"hljs-string\">"stepsItems"</span> <span class=\"hljs-attr\">:readonly</span>=<span class=\"hljs-string\">"true"</span> /></span><br> <span class=\"hljs-comment\"><!-- </span><br><span class=\"hljs-comment\"> 嵌套路由渲染区, 用于渲染步骤组件</span><br><span class=\"hljs-comment\"> :formData="formObject" 向子路由传递数据。可选,一般用于给子路由的组件传递初始值,如果不需要可以忽略</span><br><span class=\"hljs-comment\"> @prevPage="prevPage($event)" 监听子路由prevPage事件, 用于跳转到上一页(上一步)</span><br><span class=\"hljs-comment\"> @nextPage="nextPage($event)" 监听子路由nextPage事件, 用于跳转到下一页(下一步)</span><br><span class=\"hljs-comment\"> @complete="complete" 监听子路由complete事件,该事件触发时表示步骤完成</span><br><span class=\"hljs-comment\"> --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">router-view</span> </span><br><span class=\"hljs-tag\"> <span class=\"hljs-attr\">v-slot</span>=<span class=\"hljs-string\">"{ Component }"</span> </span><br><span class=\"hljs-tag\"> <span class=\"hljs-attr\">:formData</span>=<span class=\"hljs-string\">"formObject"</span> </span><br><span class=\"hljs-tag\"> @<span class=\"hljs-attr\">prevPage</span>=<span class=\"hljs-string\">"prevPage($event)"</span> </span><br><span class=\"hljs-tag\"> @<span class=\"hljs-attr\">nextPage</span>=<span class=\"hljs-string\">"nextPage($event)"</span></span><br><span class=\"hljs-tag\"> @<span class=\"hljs-attr\">complete</span>=<span class=\"hljs-string\">"complete($event)"</span></span><br><span class=\"hljs-tag\"> ></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">keep-alive</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">component</span> <span class=\"hljs-attr\">:is</span>=<span class=\"hljs-string\">"Component"</span> /></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">keep-alive</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">router-view</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> { ref } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"><span class=\"hljs-comment\">// 导入router, 用于控制子路由</span></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> { useRouter } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue-router'</span></span><br><span class=\"language-javascript\"><span class=\"hljs-comment\">// 导入 steps 组件</span></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">Steps</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'primevue/steps'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'TestView'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { <span class=\"hljs-title class_\">Steps</span> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\"></span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 路由实例, 控制子由跳转</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> router = <span class=\"hljs-title function_\">useRouter</span>()</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 步骤条信息</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> stepsItems = <span class=\"hljs-title function_\">ref</span>([</span><br><span class=\"language-javascript\"> { <span class=\"hljs-attr\">label</span>: <span class=\"hljs-string\">'步骤1'</span>, <span class=\"hljs-attr\">to</span>: <span class=\"hljs-string\">'/tv/p1'</span> },</span><br><span class=\"language-javascript\"> { <span class=\"hljs-attr\">label</span>: <span class=\"hljs-string\">'步骤2'</span>, <span class=\"hljs-attr\">to</span>: <span class=\"hljs-string\">'/tv/p2'</span> },</span><br><span class=\"language-javascript\"> { <span class=\"hljs-attr\">label</span>: <span class=\"hljs-string\">'步骤3'</span>, <span class=\"hljs-attr\">to</span>: <span class=\"hljs-string\">'/tv/p3'</span> },</span><br><span class=\"language-javascript\"> ])</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> formObject = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'Steps数据'</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 子路由事件处理函数, 跳转到下一页(下一个步骤)</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@param</span> {<span class=\"hljs-type\">*</span>} data 子路由组件传递的数据</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">nextPage</span> = (<span class=\"hljs-params\">data</span>) => {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 这里进行子路由组件数据的处理</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 这里为了演示只是向控制台打印传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">info</span>(<span class=\"hljs-string\">`Steps: <span class=\"hljs-subst\">${stepsItems.value[data.value.index].label}</span>传递的数据`</span>, data.<span class=\"hljs-property\">value</span>)</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 跳转到下一个步骤, 下一个步骤的路由信息由stepsItems定义</span></span><br><span class=\"language-javascript\"> router.<span class=\"hljs-title function_\">push</span>(stepsItems.<span class=\"hljs-property\">value</span>[data.<span class=\"hljs-property\">value</span>.<span class=\"hljs-property\">index</span> + <span class=\"hljs-number\">1</span>].<span class=\"hljs-property\">to</span>);</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 子路由事件处理函数, 跳转到上一页(上一个步骤)</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@param</span> {<span class=\"hljs-type\">*</span>} data 子路由组件传递的数据</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">prevPage</span> = (<span class=\"hljs-params\">data</span>) => {</span><br><span class=\"language-javascript\"> router.<span class=\"hljs-title function_\">push</span>(stepsItems.<span class=\"hljs-property\">value</span>[data.<span class=\"hljs-property\">value</span>.<span class=\"hljs-property\">index</span> - <span class=\"hljs-number\">1</span>].<span class=\"hljs-property\">to</span>);</span><br><span class=\"language-javascript\"> };</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 子路由事件处理函数, 步骤完成</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@param</span> {<span class=\"hljs-type\">*</span>} data 子路由组件传递的数据</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">complete</span> = (<span class=\"hljs-params\">data</span>) => {</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 这里做步骤完成后的操作, 这里为了演示只是进行了简单的提示,和打印控制台</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">info</span>(<span class=\"hljs-string\">`Steps: <span class=\"hljs-subst\">${stepsItems.value[data.value.index].label}</span>传递的数据`</span>, data.<span class=\"hljs-property\">value</span>)</span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">alert</span>(<span class=\"hljs-string\">'步骤完成'</span>)</span><br><span class=\"language-javascript\"> };</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> stepsItems, formObject,</span><br><span class=\"language-javascript\"> nextPage, prevPage, complete</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br></code></pre></td></tr></table></figure>\n\n<p>访问 <code>/tv</code> ,可以看到步骤条已经创建。</p>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/3.png\"></p>\n<h4 id=\"2-4-2-创建子路由组件\"><a href=\"#2-4-2-创建子路由组件\" class=\"headerlink\" title=\"2.4.2 创建子路由组件\"></a>2.4.2 创建子路由组件</h4><p>在 <code>primevue-steps/src/components</code> 目录下创建路由文件三个组件提供个<code>steps</code>组件使用</p>\n<ul>\n<li>P1.vue</li>\n<li>P2.vue</li>\n<li>P3.vue</li>\n</ul>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/4.png\"></p>\n<p><strong>P1.vue</strong></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>步骤一:/tv/p1<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span><br> <span class=\"hljs-comment\"><!-- 下一页控制按钮 --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"nextPage"</span>></span>下一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> {ref} <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'P1'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明接收steps组件传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">props</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: <span class=\"hljs-title class_\">Object</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明事件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">emits</span>: [<span class=\"hljs-string\">'prevPage'</span>, <span class=\"hljs-string\">'nextPage'</span>, <span class=\"hljs-string\">'complete'</span>],</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\">props, ctx</span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">log</span>(<span class=\"hljs-string\">'步骤一, Steps传递的数据:'</span>, props.<span class=\"hljs-property\">formData</span>)</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 当前组件的数据, nextPage事件发出时传递给Steps组件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> data = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'我是步骤一'</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">index</span>: <span class=\"hljs-number\">0</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">nextPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'nextPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> nextPage</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span> <span class=\"hljs-attr\">scoped</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"> <span class=\"hljs-selector-tag\">div</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">width</span>: <span class=\"hljs-number\">100%</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">height</span>: <span class=\"hljs-number\">100px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">border-radius</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">box-shadow</span>: <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">10px</span> <span class=\"hljs-number\">5px</span> <span class=\"hljs-number\">#666666</span>;</span><br><span class=\"language-css\"> }</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br></code></pre></td></tr></table></figure>\n\n<p><strong>P2.vue</strong></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>步骤二:/tv/p2<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span><br> <span class=\"hljs-comment\"><!-- 上一页,下一页控制按钮 --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"prevPage"</span>></span>上一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"nextPage"</span>></span>下一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> {ref} <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'P2'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明接收steps组件传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">props</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: <span class=\"hljs-title class_\">Object</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明事件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">emits</span>: [<span class=\"hljs-string\">'prevPage'</span>, <span class=\"hljs-string\">'nextPage'</span>, <span class=\"hljs-string\">'complete'</span>],</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\">props, ctx</span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">log</span>(<span class=\"hljs-string\">'步骤二, Steps传递的数据:'</span>, props.<span class=\"hljs-property\">formData</span>)</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 当前组件的数据, nextPage事件发出时传递给Steps组件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> data = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'我是步骤二'</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">index</span>: <span class=\"hljs-number\">1</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出nextPage事件,让steps组件控制router跳转到下一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">nextPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'nextPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出prevPage事件,让steps组件控制router跳转到上一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">prevPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'prevPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> nextPage, prevPage</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span> <span class=\"hljs-attr\">scoped</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"> <span class=\"hljs-selector-tag\">div</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">width</span>: <span class=\"hljs-number\">100%</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">height</span>: <span class=\"hljs-number\">100px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">border-radius</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">box-shadow</span>: <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">10px</span> <span class=\"hljs-number\">5px</span> <span class=\"hljs-number\">#666666</span>;</span><br><span class=\"language-css\"> }</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br></code></pre></td></tr></table></figure>\n\n<p><strong>P3.vue</strong></p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs html\"><span class=\"hljs-tag\"><<span class=\"hljs-name\">template</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>步骤三:/tv/p3<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span><br> <span class=\"hljs-comment\"><!-- 上一页,下一页控制按钮 --></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"prevPage"</span>></span>上一步<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> @<span class=\"hljs-attr\">click</span>=<span class=\"hljs-string\">"complete"</span>></span>完成/确定<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span><br> <span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span><br><span class=\"hljs-tag\"></<span class=\"hljs-name\">template</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">script</span>></span><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">import</span> {ref} <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">'vue'</span></span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">'P3'</span>,</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">components</span>: { },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明接收steps组件传递的数据</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">props</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: <span class=\"hljs-title class_\">Object</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 声明事件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">emits</span>: [<span class=\"hljs-string\">'prevPage'</span>, <span class=\"hljs-string\">'nextPage'</span>, <span class=\"hljs-string\">'complete'</span>],</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-title function_\">setup</span>(<span class=\"hljs-params\">props, ctx</span>) {</span><br><span class=\"language-javascript\"> <span class=\"hljs-variable language_\">console</span>.<span class=\"hljs-title function_\">log</span>(<span class=\"hljs-string\">'步骤三, Steps传递的数据:'</span>, props.<span class=\"hljs-property\">formData</span>)</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">// 当前组件的数据, nextPage事件发出时传递给Steps组件</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> data = <span class=\"hljs-title function_\">ref</span>({</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">formData</span>: {</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">msg</span>: <span class=\"hljs-string\">'我是步骤三'</span></span><br><span class=\"language-javascript\"> },</span><br><span class=\"language-javascript\"> <span class=\"hljs-attr\">index</span>: <span class=\"hljs-number\">2</span></span><br><span class=\"language-javascript\"> })</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出prevPage事件,让steps组件控制router跳转到下一页</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">prevPage</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'prevPage'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-comment\">/**</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> * <span class=\"hljs-doctag\">@function</span> 向steps组件发出complete事件,告知steps组件步骤完成</span></span><br><span class=\"hljs-comment\"><span class=\"language-javascript\"> */</span></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">complete</span> = (<span class=\"hljs-params\"></span>) => {</span><br><span class=\"language-javascript\"> ctx.<span class=\"hljs-title function_\">emit</span>(<span class=\"hljs-string\">'complete'</span>, data)</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> <span class=\"hljs-keyword\">return</span> {</span><br><span class=\"language-javascript\"> prevPage, complete</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"> }</span><br><span class=\"language-javascript\"></span><br><span class=\"language-javascript\"> </span><br><span class=\"language-javascript\">}</span><br><span class=\"language-javascript\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">script</span>></span><br><br><span class=\"hljs-tag\"><<span class=\"hljs-name\">style</span> <span class=\"hljs-attr\">scoped</span>></span><span class=\"language-css\"></span><br><span class=\"language-css\"> <span class=\"hljs-selector-tag\">div</span> {</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">width</span>: <span class=\"hljs-number\">100%</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">height</span>: <span class=\"hljs-number\">100px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">border-radius</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">margin-top</span>: <span class=\"hljs-number\">10px</span>;</span><br><span class=\"language-css\"> <span class=\"hljs-attribute\">box-shadow</span>: <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">0px</span> <span class=\"hljs-number\">10px</span> <span class=\"hljs-number\">5px</span> <span class=\"hljs-number\">#666666</span>;</span><br><span class=\"language-css\"> }</span><br><span class=\"language-css\"></span><span class=\"hljs-tag\"></<span class=\"hljs-name\">style</span>></span><br></code></pre></td></tr></table></figure>\n\n<h4 id=\"2-4-3-为子路由组件指定路由地址\"><a href=\"#2-4-3-为子路由组件指定路由地址\" class=\"headerlink\" title=\"2.4.3 为子路由组件指定路由地址\"></a>2.4.3 为子路由组件指定路由地址</h4><p>修改路由文件 <code>primevue-steps/src/router/index.js</code>,为TestView视图添加子路由</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs js\"><span class=\"hljs-keyword\">import</span> { createRouter, createWebHistory } <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"vue-router"</span>;<br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">HelloWorld</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/HelloWorld"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-title class_\">TestView</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/views/TestView"</span><br><span class=\"hljs-comment\">// 导入子路由组件</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-variable constant_\">P1</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/P1"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-variable constant_\">P2</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/P2"</span><br><span class=\"hljs-keyword\">import</span> <span class=\"hljs-variable constant_\">P3</span> <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">"@/components/P3"</span><br><br><br><span class=\"hljs-keyword\">const</span> routes = [<br> {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"index"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">HelloWorld</span><br> }, {<br> <span class=\"hljs-attr\">name</span>: <span class=\"hljs-string\">"testView"</span>,<br> <span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">"/tv"</span>,<br> <span class=\"hljs-attr\">component</span>: <span class=\"hljs-title class_\">TestView</span>,<br> <span class=\"hljs-comment\">// setps组件子路由</span><br> <span class=\"hljs-attr\">children</span>: [<br> {<span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">'p1'</span>, <span class=\"hljs-attr\">component</span>: <span class=\"hljs-variable constant_\">P1</span>},<br> {<span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">'p2'</span>, <span class=\"hljs-attr\">component</span>: <span class=\"hljs-variable constant_\">P2</span>},<br> {<span class=\"hljs-attr\">path</span>: <span class=\"hljs-string\">'p3'</span>, <span class=\"hljs-attr\">component</span>: <span class=\"hljs-variable constant_\">P3</span>},<br> ]<br> }<br>]<br><br><span class=\"hljs-keyword\">const</span> router = <span class=\"hljs-title function_\">createRouter</span>({<br> <span class=\"hljs-attr\">history</span>: <span class=\"hljs-title function_\">createWebHistory</span>(),<br> routes<br>})<br><br><span class=\"hljs-keyword\">export</span> <span class=\"hljs-keyword\">default</span> router;<br></code></pre></td></tr></table></figure>\n\n<p>完成后刷新页面并访问路径 <code>/tv/p1</code>,即可看到步骤页</p>\n<p><img src=\"/images/post/Use-Primevue-Steps-component-vue3/5.gif\"></p>\n<h2 id=\"3-演示Demo\"><a href=\"#3-演示Demo\" class=\"headerlink\" title=\"3. 演示Demo\"></a>3. 演示Demo</h2><p>文章中所用的测试Demo已经推送到github:<a href=\"https://github.com/mangfu26/blog-share/tree/primevue-steps\">https://github.com/mangfu26/blog-share/tree/primevue-steps</a></p>\n<p>你可以使用以下命令克隆使用</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs sh\">git <span class=\"hljs-built_in\">clone</span> -b primevue-steps https://github.com/mangfu26/blog-share.git primevue-steps<br></code></pre></td></tr></table></figure>"},{"layout":"post","title":"Docker 引擎安装","index_img":"/images/post/docker-cover.png","date":"2022-10-08T03:52:18.000Z","_content":"\n## 各操作系统的 Docker 引擎安装\n\n### Ubuntu\n\n旧版本的Docker称为 `docker`, `docker.io` 或 `docker-engine` 如果已安装,请卸载它们:\n\n```bash\nsudo apt-get remove docker docker-engine docker.io containerd runc\n```\n\n在新主机上首次安装 Docker 引擎之前,需要设置Docker存储库。之后可以从存储库安装和更新Docker。\n```bash\n# 更新apt包索引并安装包,以允许apt通过HTTPS使用存储库\nsudo apt-get update\nsudo apt-get install ca-certificates curl gnupg lsb-release \n```\n\n```bash\n# 添加Docker的官方GPG密钥\nsudo mkdir -p /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\n```\n\n```bash\n# 设置存储库\necho \\\n \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \\\n $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\n```\n\n安装 Docker 引擎\n```bash\nsudo apt-get update\n# 如果不需要 docker compose 编排工具, 可将 docker-compose-plugin 移除\nsudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin\n```\n\n## 非 root 用户使用 docker \n\n每次使用 Docker 都需要 `sudo` root 权限,有些许不方便,可以配置常用用户使用 Docker\n\n```bash\n# 创建 docker 组\nsudo groupadd docker\n\n# 将当前用户加入 docker 组, $USER 保存的是当前用户的名称, 需要添加其他用户的将 $USER \n# 替换为目标用户名称\nsudo gpasswd -a $USER docker\n\n# 重启 Docker 服务\nsudo service docker restart\n```","source":"_posts/docker-engine-install.md","raw":"---\nlayout: post\ntitle: Docker 引擎安装\nindex_img: /images/post/docker-cover.png\ndate: 2022-10-08 11:52:18\ncategories:\n- 建设\ntags: \n- Docker\n---\n\n## 各操作系统的 Docker 引擎安装\n\n### Ubuntu\n\n旧版本的Docker称为 `docker`, `docker.io` 或 `docker-engine` 如果已安装,请卸载它们:\n\n```bash\nsudo apt-get remove docker docker-engine docker.io containerd runc\n```\n\n在新主机上首次安装 Docker 引擎之前,需要设置Docker存储库。之后可以从存储库安装和更新Docker。\n```bash\n# 更新apt包索引并安装包,以允许apt通过HTTPS使用存储库\nsudo apt-get update\nsudo apt-get install ca-certificates curl gnupg lsb-release \n```\n\n```bash\n# 添加Docker的官方GPG密钥\nsudo mkdir -p /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\n```\n\n```bash\n# 设置存储库\necho \\\n \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \\\n $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\n```\n\n安装 Docker 引擎\n```bash\nsudo apt-get update\n# 如果不需要 docker compose 编排工具, 可将 docker-compose-plugin 移除\nsudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin\n```\n\n## 非 root 用户使用 docker \n\n每次使用 Docker 都需要 `sudo` root 权限,有些许不方便,可以配置常用用户使用 Docker\n\n```bash\n# 创建 docker 组\nsudo groupadd docker\n\n# 将当前用户加入 docker 组, $USER 保存的是当前用户的名称, 需要添加其他用户的将 $USER \n# 替换为目标用户名称\nsudo gpasswd -a $USER docker\n\n# 重启 Docker 服务\nsudo service docker restart\n```","slug":"docker-engine-install","published":1,"updated":"2022-11-11T02:41:02.355Z","comments":1,"photos":[],"link":"","_id":"clb4fek6l0002z0iwe86z0b68","content":"<h2 id=\"各操作系统的-Docker-引擎安装\"><a href=\"#各操作系统的-Docker-引擎安装\" class=\"headerlink\" title=\"各操作系统的 Docker 引擎安装\"></a>各操作系统的 Docker 引擎安装</h2><h3 id=\"Ubuntu\"><a href=\"#Ubuntu\" class=\"headerlink\" title=\"Ubuntu\"></a>Ubuntu</h3><p>旧版本的Docker称为 <code>docker</code>, <code>docker.io</code> 或 <code>docker-engine</code> 如果已安装,请卸载它们:</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">sudo apt-get remove docker docker-engine docker.io containerd runc<br></code></pre></td></tr></table></figure>\n\n<p>在新主机上首次安装 Docker 引擎之前,需要设置Docker存储库。之后可以从存储库安装和更新Docker。</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 更新apt包索引并安装包,以允许apt通过HTTPS使用存储库</span><br>sudo apt-get update<br>sudo apt-get install ca-certificates curl gnupg lsb-release <br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 添加Docker的官方GPG密钥</span><br>sudo <span class=\"hljs-built_in\">mkdir</span> -p /etc/apt/keyrings<br>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg<br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 设置存储库</span><br><span class=\"hljs-built_in\">echo</span> \\<br> <span class=\"hljs-string\">"deb [arch=<span class=\"hljs-subst\">$(dpkg --print-architecture)</span> signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \\</span><br><span class=\"hljs-string\"> <span class=\"hljs-subst\">$(lsb_release -cs)</span> stable"</span> | sudo <span class=\"hljs-built_in\">tee</span> /etc/apt/sources.list.d/docker.list > /dev/null<br></code></pre></td></tr></table></figure>\n\n<p>安装 Docker 引擎</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">sudo apt-get update<br><span class=\"hljs-comment\"># 如果不需要 docker compose 编排工具, 可将 docker-compose-plugin 移除</span><br>sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin<br></code></pre></td></tr></table></figure>\n\n<h2 id=\"非-root-用户使用-docker\"><a href=\"#非-root-用户使用-docker\" class=\"headerlink\" title=\"非 root 用户使用 docker\"></a>非 root 用户使用 docker</h2><p>每次使用 Docker 都需要 <code>sudo</code> root 权限,有些许不方便,可以配置常用用户使用 Docker</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 创建 docker 组</span><br>sudo groupadd docker<br><br><span class=\"hljs-comment\"># 将当前用户加入 docker 组, $USER 保存的是当前用户的名称, 需要添加其他用户的将 $USER </span><br><span class=\"hljs-comment\"># 替换为目标用户名称</span><br>sudo gpasswd -a <span class=\"hljs-variable\">$USER</span> docker<br><br><span class=\"hljs-comment\"># 重启 Docker 服务</span><br>sudo service docker restart<br></code></pre></td></tr></table></figure>","site":{"data":{}},"wordcount":1034,"excerpt":"","more":"<h2 id=\"各操作系统的-Docker-引擎安装\"><a href=\"#各操作系统的-Docker-引擎安装\" class=\"headerlink\" title=\"各操作系统的 Docker 引擎安装\"></a>各操作系统的 Docker 引擎安装</h2><h3 id=\"Ubuntu\"><a href=\"#Ubuntu\" class=\"headerlink\" title=\"Ubuntu\"></a>Ubuntu</h3><p>旧版本的Docker称为 <code>docker</code>, <code>docker.io</code> 或 <code>docker-engine</code> 如果已安装,请卸载它们:</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">sudo apt-get remove docker docker-engine docker.io containerd runc<br></code></pre></td></tr></table></figure>\n\n<p>在新主机上首次安装 Docker 引擎之前,需要设置Docker存储库。之后可以从存储库安装和更新Docker。</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 更新apt包索引并安装包,以允许apt通过HTTPS使用存储库</span><br>sudo apt-get update<br>sudo apt-get install ca-certificates curl gnupg lsb-release <br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 添加Docker的官方GPG密钥</span><br>sudo <span class=\"hljs-built_in\">mkdir</span> -p /etc/apt/keyrings<br>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg<br></code></pre></td></tr></table></figure>\n\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 设置存储库</span><br><span class=\"hljs-built_in\">echo</span> \\<br> <span class=\"hljs-string\">"deb [arch=<span class=\"hljs-subst\">$(dpkg --print-architecture)</span> signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \\</span><br><span class=\"hljs-string\"> <span class=\"hljs-subst\">$(lsb_release -cs)</span> stable"</span> | sudo <span class=\"hljs-built_in\">tee</span> /etc/apt/sources.list.d/docker.list > /dev/null<br></code></pre></td></tr></table></figure>\n\n<p>安装 Docker 引擎</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">sudo apt-get update<br><span class=\"hljs-comment\"># 如果不需要 docker compose 编排工具, 可将 docker-compose-plugin 移除</span><br>sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin<br></code></pre></td></tr></table></figure>\n\n<h2 id=\"非-root-用户使用-docker\"><a href=\"#非-root-用户使用-docker\" class=\"headerlink\" title=\"非 root 用户使用 docker\"></a>非 root 用户使用 docker</h2><p>每次使用 Docker 都需要 <code>sudo</code> root 权限,有些许不方便,可以配置常用用户使用 Docker</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-comment\"># 创建 docker 组</span><br>sudo groupadd docker<br><br><span class=\"hljs-comment\"># 将当前用户加入 docker 组, $USER 保存的是当前用户的名称, 需要添加其他用户的将 $USER </span><br><span class=\"hljs-comment\"># 替换为目标用户名称</span><br>sudo gpasswd -a <span class=\"hljs-variable\">$USER</span> docker<br><br><span class=\"hljs-comment\"># 重启 Docker 服务</span><br>sudo service docker restart<br></code></pre></td></tr></table></figure>"},{"title":"Hello World","date":"2022-05-31T16:00:01.000Z","_content":"\n# 🚩 我的博客/知识库诞生了","source":"_posts/hello-world.md","raw":"---\ntitle: Hello World\ndate: 2022-06-01 00:00:01\n---\n\n# 🚩 我的博客/知识库诞生了","slug":"hello-world","published":1,"updated":"2022-11-05T16:03:53.013Z","comments":1,"layout":"post","photos":[],"link":"","_id":"clb4fek6r0005z0iwb2zf42f0","content":"<h1 id=\"🚩-我的博客-x2F-知识库诞生了\"><a href=\"#🚩-我的博客-x2F-知识库诞生了\" class=\"headerlink\" title=\"🚩 我的博客/知识库诞生了\"></a>🚩 我的博客/知识库诞生了</h1>","site":{"data":{}},"wordcount":18,"excerpt":"","more":"<h1 id=\"🚩-我的博客-x2F-知识库诞生了\"><a href=\"#🚩-我的博客-x2F-知识库诞生了\" class=\"headerlink\" title=\"🚩 我的博客/知识库诞生了\"></a>🚩 我的博客/知识库诞生了</h1>"},{"layout":"post","title":"Docker容器/etc/hosts文件被重置Bug","index_img":"/images/post/bug-diary-cover.png","date":"2022-08-16T08:13:34.000Z","_content":"\n## 1. Bug发现\n\n前些日子,公司有个将Awvs14打包为一个独立的Docker容器并暴露接口和数据库给其他服务做测试的需求\n\n出于测试目的,便在 [🔰雨苁ℒ🔰](https://www.ddosi.org/) 大佬的博客中找了个AWVS14的Linux破解版\n\n具体的破解教程以及破解文件等可以参考:[Awvs破解版14.7.220228146|awvs cracked](https://www.ddosi.org/awvs-14-7/),本篇日记只专注Bug记录\n\n根据大佬提供的安装教程一路走下来顺顺利利安装完成\n\n接下来自然而然的就是导出容器推送到服务器进行测试\n\n> 小提示:\n>\n> 容器内安装Awvs需要安装Awvs所需的依赖,可以根据Awvs版本去查看官方的文档安装依赖,在本篇日记中容器使用的是 `ubuntu20.04` 基础镜像\n> \n> Awvs的依赖安装如下:\n>\n> ```shell\n> apt install -y libxdamage1 libgtk-3-0 libasound2 libnss3 libxss1 libx11-xcb1 libxcb-dri3-0 libgbm1 libdrm2 libxshmfence1 sudo\n> ```\n\n但是推送到服务器后使用 `docker run` 命令启动容器时怪事发生了,扫描任务一直提示启动失败\n\n排除Awvs容器的输出发现每当任务启动时都会提示许可证错误,起初以为是破解文件的问题(因为安装后就直接打包推送到服务器测试,没有在本地启动测试过)\n\n于是重新构建一个容器,在本地测试没问题后推送到服务器,但任务启也是一直失败,错误原因也同样是许可证错误\n\n........\n\n有怀疑过是网络问题,有怀疑过Docker版本问题,有怀疑过是Awvs许可证与Mac地址相关等等,耽搁了一个周,焦头烂额准备放弃之际打算对比下本地容器和测试服务上的容器内部文件有什么不一样\n\n之前从未怀疑过是容器文件不一致导致的Bug,因为在我的认知里,容器导出后再导入再运行内部文件是不会变化的,就像传统虚拟机一样\n\n但是对比过后,发现测试服务器上的 `/etc/hosts` 文件与本地打包的容器不一致\n\n根据大佬的 Awvs14 Linux 版安装教程,在第6步时需要修改 `/etc/hosts` 文件\n\n![](images/post/docker-container-etc-hosts-file-reset-bug/01.png)\n\n这一步在正常的Linux操作系统上操作是没问题的,所以理所当然的以为打包后的 `/etc/hosts` 文件也不会改变\n\n由于 `/etc/hosts` 中与破解相关的内容被清除了,所以AWVS任务因为许可证问题启动失败也是情理之中了\n\n\n## 2. 为什么 /etc/hosts 会被重置?\n\n参考Docker官方文档:[https://docs.docker.com/engine/reference/run/#managing-etchosts](https://docs.docker.com/engine/reference/run/#managing-etchosts)\n\n![](images/post/docker-container-etc-hosts-file-reset-bug/02.png)\n\n> 你的容器在/etc/hosts中会有几行,它们定义了容器本身的主机名以及localhost和其他一些常见的东西。--add-host标志可以用来向/etc/hosts添加额外的行。\n>\n> 如果一个容器被连接到默认的桥接网络并与其他容器链接,那么该容器的/etc/hosts文件就会用被链接的容器的名称进行更新。\n>\n> 由于Docker可能会实时更新容器的/etc/hosts文件,所以可能会出现这样的情况:容器内的进程最终会读取一个空的或不完整的/etc/hosts文件。在大多数情况下,再次重试读取应该可以解决问题。\n\n也就是说Docker会对 `/etc/hosts` 文件进行管理并且会不定时更新\n\n我猜测是我启动测试容器时docker会检查网络并更新 `/etc/hosts` 文件导致破解内容被清除导致\n\n\n## 3. Bug解决\n\n### 3.1 --add-host\n\n> 如果你只是对已有镜像做简单修改,建议使用此种方式\n\n创建容器时使用 `docker run` 命令的 `--add-host` 参数指定 /etc/hosts 内容\n\n命令格式:\n\n```shell\n# host : 主机名称\n# ip : 主机IP地址\ndocker run --add-host host:ip\n```\n\n\n### 3.2 使用启动脚本\n\n> 如果你使用Dockerfile构建镜像且使用启动脚本做初始化操作时建议使用此种方式\n\n第二种方式是构建镜像时指定一个启动脚本,每次启动容器前检查一次 `/etc/hosts` 文件内容完整性\n\n以AWVS破解教程为基础,以下为一个shell启动脚本例子:\n\n该启动脚本会在容器启动时执行,脚本会检查 `/etc/hosts` 文件中是否存在破解内容\n\n127.0.0.1 updates.acunetix.com\n127.0.0.1 erp.acunetix.com\n\n```bash\n#!/bin/bash\n\n# 每次启动前都检查 /etc/hosts 文件, 确保屏蔽了AWVS更新检查\n# 防止容器迁移后 /etc/hosts 文件内容丢失造成的扫描任务启动失败\nhost1CheckResult=`cat /etc/hosts | grep updates.acunetix.com | tr -s [:space:]`\nhost2CheckResult=`cat /etc/hosts | grep erp.acunetix.com | tr -s [:space:]`\nif [ -z \"$host1CheckResult\" ];then\n echo \"127.0.0.1 updates.acunetix.com\" >> /etc/hosts\nfi\nif [ -z \"$host2CheckResult\" ];then\n echo \"127.0.0.1 erp.acunetix.com\" >> /etc/hosts\nfi\n\n# 启动AWVS\nsu - acunetix -c \"cd /home/acunetix/.acunetix/ && ./start.sh\"\n```\n\n将此脚本保存为 `start.sh`\n\n\n## 4. 一些参考命令 \n\n### 4.1 将启动脚本附加到已有容器 \n\n将脚本复制到容器中 \n\n```shell\ndocker cp start.sh 容器名称:脚本存储目录\n# 例子\ndocker cp start.sh awvs-14:/root/\n```\n\n给脚本添加执行权限 \n\n```shell\ndocker exec 容器名称 chmod +x 脚本路径\n# 例子\ndocker exec awvs-14 chmod +x /root/start.sh\n```\n\n停止容器\n\n```shell\ndocker stop 容器名称\n# 例子\ndocker stop awvs-14\n```\n\n将容器提交为新镜像\n\n```shell\ndocker commit 容器名称 镜像名称:tag\n# 例子\ndocker commit awvs-14 awvs:14\n```\n\n以提交的镜像作为基础启动一个新镜像,并以 `start.sh` 作为启动脚本\n\n```shell\ndocker run -itd --name awvs-14-new awvs:14 /root/start.sh\n```\n\n### 4.2 使用Dockerfile构建并启动\n\n```dockerfile\nFROM ubuntu:20.04\n\nWORKDIR /root/\nCOPY start.sh ./\n\nRUN chmod +x ./start.sh\n\nCMD ./start.sh\n```\n\n构建镜像\n\n```shell\ndocker build -t awvs:14 .\n```\n\n以镜像为基础启动容器\n\n```shell\ndocker run -itd --name awvs-14-new awvs:14 \n```","source":"_posts/docker-container-etc-hosts-file-reset-bug.md","raw":"---\nlayout: post\ntitle: Docker容器/etc/hosts文件被重置Bug\nindex_img: /images/post/bug-diary-cover.png\ndate: 2022-08-16 16:13:34\ncategories:\n- Bug日记\ntags:\n- Docker\n- Bug\n---\n\n## 1. Bug发现\n\n前些日子,公司有个将Awvs14打包为一个独立的Docker容器并暴露接口和数据库给其他服务做测试的需求\n\n出于测试目的,便在 [🔰雨苁ℒ🔰](https://www.ddosi.org/) 大佬的博客中找了个AWVS14的Linux破解版\n\n具体的破解教程以及破解文件等可以参考:[Awvs破解版14.7.220228146|awvs cracked](https://www.ddosi.org/awvs-14-7/),本篇日记只专注Bug记录\n\n根据大佬提供的安装教程一路走下来顺顺利利安装完成\n\n接下来自然而然的就是导出容器推送到服务器进行测试\n\n> 小提示:\n>\n> 容器内安装Awvs需要安装Awvs所需的依赖,可以根据Awvs版本去查看官方的文档安装依赖,在本篇日记中容器使用的是 `ubuntu20.04` 基础镜像\n> \n> Awvs的依赖安装如下:\n>\n> ```shell\n> apt install -y libxdamage1 libgtk-3-0 libasound2 libnss3 libxss1 libx11-xcb1 libxcb-dri3-0 libgbm1 libdrm2 libxshmfence1 sudo\n> ```\n\n但是推送到服务器后使用 `docker run` 命令启动容器时怪事发生了,扫描任务一直提示启动失败\n\n排除Awvs容器的输出发现每当任务启动时都会提示许可证错误,起初以为是破解文件的问题(因为安装后就直接打包推送到服务器测试,没有在本地启动测试过)\n\n于是重新构建一个容器,在本地测试没问题后推送到服务器,但任务启也是一直失败,错误原因也同样是许可证错误\n\n........\n\n有怀疑过是网络问题,有怀疑过Docker版本问题,有怀疑过是Awvs许可证与Mac地址相关等等,耽搁了一个周,焦头烂额准备放弃之际打算对比下本地容器和测试服务上的容器内部文件有什么不一样\n\n之前从未怀疑过是容器文件不一致导致的Bug,因为在我的认知里,容器导出后再导入再运行内部文件是不会变化的,就像传统虚拟机一样\n\n但是对比过后,发现测试服务器上的 `/etc/hosts` 文件与本地打包的容器不一致\n\n根据大佬的 Awvs14 Linux 版安装教程,在第6步时需要修改 `/etc/hosts` 文件\n\n![](images/post/docker-container-etc-hosts-file-reset-bug/01.png)\n\n这一步在正常的Linux操作系统上操作是没问题的,所以理所当然的以为打包后的 `/etc/hosts` 文件也不会改变\n\n由于 `/etc/hosts` 中与破解相关的内容被清除了,所以AWVS任务因为许可证问题启动失败也是情理之中了\n\n\n## 2. 为什么 /etc/hosts 会被重置?\n\n参考Docker官方文档:[https://docs.docker.com/engine/reference/run/#managing-etchosts](https://docs.docker.com/engine/reference/run/#managing-etchosts)\n\n![](images/post/docker-container-etc-hosts-file-reset-bug/02.png)\n\n> 你的容器在/etc/hosts中会有几行,它们定义了容器本身的主机名以及localhost和其他一些常见的东西。--add-host标志可以用来向/etc/hosts添加额外的行。\n>\n> 如果一个容器被连接到默认的桥接网络并与其他容器链接,那么该容器的/etc/hosts文件就会用被链接的容器的名称进行更新。\n>\n> 由于Docker可能会实时更新容器的/etc/hosts文件,所以可能会出现这样的情况:容器内的进程最终会读取一个空的或不完整的/etc/hosts文件。在大多数情况下,再次重试读取应该可以解决问题。\n\n也就是说Docker会对 `/etc/hosts` 文件进行管理并且会不定时更新\n\n我猜测是我启动测试容器时docker会检查网络并更新 `/etc/hosts` 文件导致破解内容被清除导致\n\n\n## 3. Bug解决\n\n### 3.1 --add-host\n\n> 如果你只是对已有镜像做简单修改,建议使用此种方式\n\n创建容器时使用 `docker run` 命令的 `--add-host` 参数指定 /etc/hosts 内容\n\n命令格式:\n\n```shell\n# host : 主机名称\n# ip : 主机IP地址\ndocker run --add-host host:ip\n```\n\n\n### 3.2 使用启动脚本\n\n> 如果你使用Dockerfile构建镜像且使用启动脚本做初始化操作时建议使用此种方式\n\n第二种方式是构建镜像时指定一个启动脚本,每次启动容器前检查一次 `/etc/hosts` 文件内容完整性\n\n以AWVS破解教程为基础,以下为一个shell启动脚本例子:\n\n该启动脚本会在容器启动时执行,脚本会检查 `/etc/hosts` 文件中是否存在破解内容\n\n127.0.0.1 updates.acunetix.com\n127.0.0.1 erp.acunetix.com\n\n```bash\n#!/bin/bash\n\n# 每次启动前都检查 /etc/hosts 文件, 确保屏蔽了AWVS更新检查\n# 防止容器迁移后 /etc/hosts 文件内容丢失造成的扫描任务启动失败\nhost1CheckResult=`cat /etc/hosts | grep updates.acunetix.com | tr -s [:space:]`\nhost2CheckResult=`cat /etc/hosts | grep erp.acunetix.com | tr -s [:space:]`\nif [ -z \"$host1CheckResult\" ];then\n echo \"127.0.0.1 updates.acunetix.com\" >> /etc/hosts\nfi\nif [ -z \"$host2CheckResult\" ];then\n echo \"127.0.0.1 erp.acunetix.com\" >> /etc/hosts\nfi\n\n# 启动AWVS\nsu - acunetix -c \"cd /home/acunetix/.acunetix/ && ./start.sh\"\n```\n\n将此脚本保存为 `start.sh`\n\n\n## 4. 一些参考命令 \n\n### 4.1 将启动脚本附加到已有容器 \n\n将脚本复制到容器中 \n\n```shell\ndocker cp start.sh 容器名称:脚本存储目录\n# 例子\ndocker cp start.sh awvs-14:/root/\n```\n\n给脚本添加执行权限 \n\n```shell\ndocker exec 容器名称 chmod +x 脚本路径\n# 例子\ndocker exec awvs-14 chmod +x /root/start.sh\n```\n\n停止容器\n\n```shell\ndocker stop 容器名称\n# 例子\ndocker stop awvs-14\n```\n\n将容器提交为新镜像\n\n```shell\ndocker commit 容器名称 镜像名称:tag\n# 例子\ndocker commit awvs-14 awvs:14\n```\n\n以提交的镜像作为基础启动一个新镜像,并以 `start.sh` 作为启动脚本\n\n```shell\ndocker run -itd --name awvs-14-new awvs:14 /root/start.sh\n```\n\n### 4.2 使用Dockerfile构建并启动\n\n```dockerfile\nFROM ubuntu:20.04\n\nWORKDIR /root/\nCOPY start.sh ./\n\nRUN chmod +x ./start.sh\n\nCMD ./start.sh\n```\n\n构建镜像\n\n```shell\ndocker build -t awvs:14 .\n```\n\n以镜像为基础启动容器\n\n```shell\ndocker run -itd --name awvs-14-new awvs:14 \n```","slug":"docker-container-etc-hosts-file-reset-bug","published":1,"updated":"2022-08-16T10:35:25.921Z","_id":"clb4fek6s0006z0iw11hdcegc","comments":1,"photos":[],"link":"","content":"<h2 id=\"1-Bug发现\"><a href=\"#1-Bug发现\" class=\"headerlink\" title=\"1. Bug发现\"></a>1. Bug发现</h2><p>前些日子,公司有个将Awvs14打包为一个独立的Docker容器并暴露接口和数据库给其他服务做测试的需求</p>\n<p>出于测试目的,便在 <a href=\"https://www.ddosi.org/\">🔰雨苁ℒ🔰</a> 大佬的博客中找了个AWVS14的Linux破解版</p>\n<p>具体的破解教程以及破解文件等可以参考:<a href=\"https://www.ddosi.org/awvs-14-7/\">Awvs破解版14.7.220228146|awvs cracked</a>,本篇日记只专注Bug记录</p>\n<p>根据大佬提供的安装教程一路走下来顺顺利利安装完成</p>\n<p>接下来自然而然的就是导出容器推送到服务器进行测试</p>\n<blockquote>\n<p>小提示:</p>\n<p>容器内安装Awvs需要安装Awvs所需的依赖,可以根据Awvs版本去查看官方的文档安装依赖,在本篇日记中容器使用的是 <code>ubuntu20.04</code> 基础镜像</p>\n<p>Awvs的依赖安装如下:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apt install -y libxdamage1 libgtk-3-0 libasound2 libnss3 libxss1 libx11-xcb1 libxcb-dri3-0 libgbm1 libdrm2 libxshmfence1 sudo<br></code></pre></td></tr></table></figure>\n</blockquote>\n<p>但是推送到服务器后使用 <code>docker run</code> 命令启动容器时怪事发生了,扫描任务一直提示启动失败</p>\n<p>排除Awvs容器的输出发现每当任务启动时都会提示许可证错误,起初以为是破解文件的问题(因为安装后就直接打包推送到服务器测试,没有在本地启动测试过)</p>\n<p>于是重新构建一个容器,在本地测试没问题后推送到服务器,但任务启也是一直失败,错误原因也同样是许可证错误</p>\n<p>……..</p>\n<p>有怀疑过是网络问题,有怀疑过Docker版本问题,有怀疑过是Awvs许可证与Mac地址相关等等,耽搁了一个周,焦头烂额准备放弃之际打算对比下本地容器和测试服务上的容器内部文件有什么不一样</p>\n<p>之前从未怀疑过是容器文件不一致导致的Bug,因为在我的认知里,容器导出后再导入再运行内部文件是不会变化的,就像传统虚拟机一样</p>\n<p>但是对比过后,发现测试服务器上的 <code>/etc/hosts</code> 文件与本地打包的容器不一致</p>\n<p>根据大佬的 Awvs14 Linux 版安装教程,在第6步时需要修改 <code>/etc/hosts</code> 文件</p>\n<p><img src=\"/images/post/docker-container-etc-hosts-file-reset-bug/01.png\"></p>\n<p>这一步在正常的Linux操作系统上操作是没问题的,所以理所当然的以为打包后的 <code>/etc/hosts</code> 文件也不会改变</p>\n<p>由于 <code>/etc/hosts</code> 中与破解相关的内容被清除了,所以AWVS任务因为许可证问题启动失败也是情理之中了</p>\n<h2 id=\"2-为什么-x2F-etc-x2F-hosts-会被重置?\"><a href=\"#2-为什么-x2F-etc-x2F-hosts-会被重置?\" class=\"headerlink\" title=\"2. 为什么 /etc/hosts 会被重置?\"></a>2. 为什么 /etc/hosts 会被重置?</h2><p>参考Docker官方文档:<a href=\"https://docs.docker.com/engine/reference/run/#managing-etchosts\">https://docs.docker.com/engine/reference/run/#managing-etchosts</a></p>\n<p><img src=\"/images/post/docker-container-etc-hosts-file-reset-bug/02.png\"></p>\n<blockquote>\n<p>你的容器在/etc/hosts中会有几行,它们定义了容器本身的主机名以及localhost和其他一些常见的东西。–add-host标志可以用来向/etc/hosts添加额外的行。</p>\n<p>如果一个容器被连接到默认的桥接网络并与其他容器链接,那么该容器的/etc/hosts文件就会用被链接的容器的名称进行更新。</p>\n<p>由于Docker可能会实时更新容器的/etc/hosts文件,所以可能会出现这样的情况:容器内的进程最终会读取一个空的或不完整的/etc/hosts文件。在大多数情况下,再次重试读取应该可以解决问题。</p>\n</blockquote>\n<p>也就是说Docker会对 <code>/etc/hosts</code> 文件进行管理并且会不定时更新</p>\n<p>我猜测是我启动测试容器时docker会检查网络并更新 <code>/etc/hosts</code> 文件导致破解内容被清除导致</p>\n<h2 id=\"3-Bug解决\"><a href=\"#3-Bug解决\" class=\"headerlink\" title=\"3. Bug解决\"></a>3. Bug解决</h2><h3 id=\"3-1-–add-host\"><a href=\"#3-1-–add-host\" class=\"headerlink\" title=\"3.1 –add-host\"></a>3.1 –add-host</h3><blockquote>\n<p>如果你只是对已有镜像做简单修改,建议使用此种方式</p>\n</blockquote>\n<p>创建容器时使用 <code>docker run</code> 命令的 <code>--add-host</code> 参数指定 /etc/hosts 内容</p>\n<p>命令格式:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\"><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">host : 主机名称</span><br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">ip : 主机IP地址</span><br>docker run --add-host host:ip<br></code></pre></td></tr></table></figure>\n\n\n<h3 id=\"3-2-使用启动脚本\"><a href=\"#3-2-使用启动脚本\" class=\"headerlink\" title=\"3.2 使用启动脚本\"></a>3.2 使用启动脚本</h3><blockquote>\n<p>如果你使用Dockerfile构建镜像且使用启动脚本做初始化操作时建议使用此种方式</p>\n</blockquote>\n<p>第二种方式是构建镜像时指定一个启动脚本,每次启动容器前检查一次 <code>/etc/hosts</code> 文件内容完整性</p>\n<p>以AWVS破解教程为基础,以下为一个shell启动脚本例子:</p>\n<p>该启动脚本会在容器启动时执行,脚本会检查 <code>/etc/hosts</code> 文件中是否存在破解内容</p>\n<p>127.0.0.1 updates.acunetix.com<br>127.0.0.1 erp.acunetix.com</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-meta\">#!/bin/bash</span><br><br><span class=\"hljs-comment\"># 每次启动前都检查 /etc/hosts 文件, 确保屏蔽了AWVS更新检查</span><br><span class=\"hljs-comment\"># 防止容器迁移后 /etc/hosts 文件内容丢失造成的扫描任务启动失败</span><br>host1CheckResult=`<span class=\"hljs-built_in\">cat</span> /etc/hosts | grep updates.acunetix.com | <span class=\"hljs-built_in\">tr</span> -s [:space:]`<br>host2CheckResult=`<span class=\"hljs-built_in\">cat</span> /etc/hosts | grep erp.acunetix.com | <span class=\"hljs-built_in\">tr</span> -s [:space:]`<br><span class=\"hljs-keyword\">if</span> [ -z <span class=\"hljs-string\">"<span class=\"hljs-variable\">$host1CheckResult</span>"</span> ];<span class=\"hljs-keyword\">then</span><br> <span class=\"hljs-built_in\">echo</span> <span class=\"hljs-string\">"127.0.0.1 updates.acunetix.com"</span> >> /etc/hosts<br><span class=\"hljs-keyword\">fi</span><br><span class=\"hljs-keyword\">if</span> [ -z <span class=\"hljs-string\">"<span class=\"hljs-variable\">$host2CheckResult</span>"</span> ];<span class=\"hljs-keyword\">then</span><br> <span class=\"hljs-built_in\">echo</span> <span class=\"hljs-string\">"127.0.0.1 erp.acunetix.com"</span> >> /etc/hosts<br><span class=\"hljs-keyword\">fi</span><br><br><span class=\"hljs-comment\"># 启动AWVS</span><br>su - acunetix -c <span class=\"hljs-string\">"cd /home/acunetix/.acunetix/ && ./start.sh"</span><br></code></pre></td></tr></table></figure>\n\n<p>将此脚本保存为 <code>start.sh</code></p>\n<h2 id=\"4-一些参考命令\"><a href=\"#4-一些参考命令\" class=\"headerlink\" title=\"4. 一些参考命令\"></a>4. 一些参考命令</h2><h3 id=\"4-1-将启动脚本附加到已有容器\"><a href=\"#4-1-将启动脚本附加到已有容器\" class=\"headerlink\" title=\"4.1 将启动脚本附加到已有容器\"></a>4.1 将启动脚本附加到已有容器</h3><p>将脚本复制到容器中 </p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker cp start.sh 容器名称:脚本存储目录<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker cp start.sh awvs-14:/root/<br></code></pre></td></tr></table></figure>\n\n<p>给脚本添加执行权限 </p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker exec 容器名称 chmod +x 脚本路径<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker exec awvs-14 chmod +x /root/start.sh<br></code></pre></td></tr></table></figure>\n\n<p>停止容器</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker stop 容器名称<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker stop awvs-14<br></code></pre></td></tr></table></figure>\n\n<p>将容器提交为新镜像</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker commit 容器名称 镜像名称:tag<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker commit awvs-14 awvs:14<br></code></pre></td></tr></table></figure>\n\n<p>以提交的镜像作为基础启动一个新镜像,并以 <code>start.sh</code> 作为启动脚本</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker run -itd --name awvs-14-new awvs:14 /root/start.sh<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"4-2-使用Dockerfile构建并启动\"><a href=\"#4-2-使用Dockerfile构建并启动\" class=\"headerlink\" title=\"4.2 使用Dockerfile构建并启动\"></a>4.2 使用Dockerfile构建并启动</h3><figure class=\"highlight dockerfile\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs dockerfile\"><span class=\"hljs-keyword\">FROM</span> ubuntu:<span class=\"hljs-number\">20.04</span><br><br><span class=\"hljs-keyword\">WORKDIR</span><span class=\"language-bash\"> /root/</span><br><span class=\"hljs-keyword\">COPY</span><span class=\"language-bash\"> start.sh ./</span><br><br><span class=\"hljs-keyword\">RUN</span><span class=\"language-bash\"> <span class=\"hljs-built_in\">chmod</span> +x ./start.sh</span><br><br><span class=\"hljs-keyword\">CMD</span><span class=\"language-bash\"> ./start.sh</span><br></code></pre></td></tr></table></figure>\n\n<p>构建镜像</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker build -t awvs:14 .<br></code></pre></td></tr></table></figure>\n\n<p>以镜像为基础启动容器</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker run -itd --name awvs-14-new awvs:14 <br></code></pre></td></tr></table></figure>","site":{"data":{}},"wordcount":2880,"excerpt":"","more":"<h2 id=\"1-Bug发现\"><a href=\"#1-Bug发现\" class=\"headerlink\" title=\"1. Bug发现\"></a>1. Bug发现</h2><p>前些日子,公司有个将Awvs14打包为一个独立的Docker容器并暴露接口和数据库给其他服务做测试的需求</p>\n<p>出于测试目的,便在 <a href=\"https://www.ddosi.org/\">🔰雨苁ℒ🔰</a> 大佬的博客中找了个AWVS14的Linux破解版</p>\n<p>具体的破解教程以及破解文件等可以参考:<a href=\"https://www.ddosi.org/awvs-14-7/\">Awvs破解版14.7.220228146|awvs cracked</a>,本篇日记只专注Bug记录</p>\n<p>根据大佬提供的安装教程一路走下来顺顺利利安装完成</p>\n<p>接下来自然而然的就是导出容器推送到服务器进行测试</p>\n<blockquote>\n<p>小提示:</p>\n<p>容器内安装Awvs需要安装Awvs所需的依赖,可以根据Awvs版本去查看官方的文档安装依赖,在本篇日记中容器使用的是 <code>ubuntu20.04</code> 基础镜像</p>\n<p>Awvs的依赖安装如下:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apt install -y libxdamage1 libgtk-3-0 libasound2 libnss3 libxss1 libx11-xcb1 libxcb-dri3-0 libgbm1 libdrm2 libxshmfence1 sudo<br></code></pre></td></tr></table></figure>\n</blockquote>\n<p>但是推送到服务器后使用 <code>docker run</code> 命令启动容器时怪事发生了,扫描任务一直提示启动失败</p>\n<p>排除Awvs容器的输出发现每当任务启动时都会提示许可证错误,起初以为是破解文件的问题(因为安装后就直接打包推送到服务器测试,没有在本地启动测试过)</p>\n<p>于是重新构建一个容器,在本地测试没问题后推送到服务器,但任务启也是一直失败,错误原因也同样是许可证错误</p>\n<p>……..</p>\n<p>有怀疑过是网络问题,有怀疑过Docker版本问题,有怀疑过是Awvs许可证与Mac地址相关等等,耽搁了一个周,焦头烂额准备放弃之际打算对比下本地容器和测试服务上的容器内部文件有什么不一样</p>\n<p>之前从未怀疑过是容器文件不一致导致的Bug,因为在我的认知里,容器导出后再导入再运行内部文件是不会变化的,就像传统虚拟机一样</p>\n<p>但是对比过后,发现测试服务器上的 <code>/etc/hosts</code> 文件与本地打包的容器不一致</p>\n<p>根据大佬的 Awvs14 Linux 版安装教程,在第6步时需要修改 <code>/etc/hosts</code> 文件</p>\n<p><img src=\"/images/post/docker-container-etc-hosts-file-reset-bug/01.png\"></p>\n<p>这一步在正常的Linux操作系统上操作是没问题的,所以理所当然的以为打包后的 <code>/etc/hosts</code> 文件也不会改变</p>\n<p>由于 <code>/etc/hosts</code> 中与破解相关的内容被清除了,所以AWVS任务因为许可证问题启动失败也是情理之中了</p>\n<h2 id=\"2-为什么-x2F-etc-x2F-hosts-会被重置?\"><a href=\"#2-为什么-x2F-etc-x2F-hosts-会被重置?\" class=\"headerlink\" title=\"2. 为什么 /etc/hosts 会被重置?\"></a>2. 为什么 /etc/hosts 会被重置?</h2><p>参考Docker官方文档:<a href=\"https://docs.docker.com/engine/reference/run/#managing-etchosts\">https://docs.docker.com/engine/reference/run/#managing-etchosts</a></p>\n<p><img src=\"/images/post/docker-container-etc-hosts-file-reset-bug/02.png\"></p>\n<blockquote>\n<p>你的容器在/etc/hosts中会有几行,它们定义了容器本身的主机名以及localhost和其他一些常见的东西。–add-host标志可以用来向/etc/hosts添加额外的行。</p>\n<p>如果一个容器被连接到默认的桥接网络并与其他容器链接,那么该容器的/etc/hosts文件就会用被链接的容器的名称进行更新。</p>\n<p>由于Docker可能会实时更新容器的/etc/hosts文件,所以可能会出现这样的情况:容器内的进程最终会读取一个空的或不完整的/etc/hosts文件。在大多数情况下,再次重试读取应该可以解决问题。</p>\n</blockquote>\n<p>也就是说Docker会对 <code>/etc/hosts</code> 文件进行管理并且会不定时更新</p>\n<p>我猜测是我启动测试容器时docker会检查网络并更新 <code>/etc/hosts</code> 文件导致破解内容被清除导致</p>\n<h2 id=\"3-Bug解决\"><a href=\"#3-Bug解决\" class=\"headerlink\" title=\"3. Bug解决\"></a>3. Bug解决</h2><h3 id=\"3-1-–add-host\"><a href=\"#3-1-–add-host\" class=\"headerlink\" title=\"3.1 –add-host\"></a>3.1 –add-host</h3><blockquote>\n<p>如果你只是对已有镜像做简单修改,建议使用此种方式</p>\n</blockquote>\n<p>创建容器时使用 <code>docker run</code> 命令的 <code>--add-host</code> 参数指定 /etc/hosts 内容</p>\n<p>命令格式:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\"><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">host : 主机名称</span><br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">ip : 主机IP地址</span><br>docker run --add-host host:ip<br></code></pre></td></tr></table></figure>\n\n\n<h3 id=\"3-2-使用启动脚本\"><a href=\"#3-2-使用启动脚本\" class=\"headerlink\" title=\"3.2 使用启动脚本\"></a>3.2 使用启动脚本</h3><blockquote>\n<p>如果你使用Dockerfile构建镜像且使用启动脚本做初始化操作时建议使用此种方式</p>\n</blockquote>\n<p>第二种方式是构建镜像时指定一个启动脚本,每次启动容器前检查一次 <code>/etc/hosts</code> 文件内容完整性</p>\n<p>以AWVS破解教程为基础,以下为一个shell启动脚本例子:</p>\n<p>该启动脚本会在容器启动时执行,脚本会检查 <code>/etc/hosts</code> 文件中是否存在破解内容</p>\n<p>127.0.0.1 updates.acunetix.com<br>127.0.0.1 erp.acunetix.com</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\"><span class=\"hljs-meta\">#!/bin/bash</span><br><br><span class=\"hljs-comment\"># 每次启动前都检查 /etc/hosts 文件, 确保屏蔽了AWVS更新检查</span><br><span class=\"hljs-comment\"># 防止容器迁移后 /etc/hosts 文件内容丢失造成的扫描任务启动失败</span><br>host1CheckResult=`<span class=\"hljs-built_in\">cat</span> /etc/hosts | grep updates.acunetix.com | <span class=\"hljs-built_in\">tr</span> -s [:space:]`<br>host2CheckResult=`<span class=\"hljs-built_in\">cat</span> /etc/hosts | grep erp.acunetix.com | <span class=\"hljs-built_in\">tr</span> -s [:space:]`<br><span class=\"hljs-keyword\">if</span> [ -z <span class=\"hljs-string\">"<span class=\"hljs-variable\">$host1CheckResult</span>"</span> ];<span class=\"hljs-keyword\">then</span><br> <span class=\"hljs-built_in\">echo</span> <span class=\"hljs-string\">"127.0.0.1 updates.acunetix.com"</span> >> /etc/hosts<br><span class=\"hljs-keyword\">fi</span><br><span class=\"hljs-keyword\">if</span> [ -z <span class=\"hljs-string\">"<span class=\"hljs-variable\">$host2CheckResult</span>"</span> ];<span class=\"hljs-keyword\">then</span><br> <span class=\"hljs-built_in\">echo</span> <span class=\"hljs-string\">"127.0.0.1 erp.acunetix.com"</span> >> /etc/hosts<br><span class=\"hljs-keyword\">fi</span><br><br><span class=\"hljs-comment\"># 启动AWVS</span><br>su - acunetix -c <span class=\"hljs-string\">"cd /home/acunetix/.acunetix/ && ./start.sh"</span><br></code></pre></td></tr></table></figure>\n\n<p>将此脚本保存为 <code>start.sh</code></p>\n<h2 id=\"4-一些参考命令\"><a href=\"#4-一些参考命令\" class=\"headerlink\" title=\"4. 一些参考命令\"></a>4. 一些参考命令</h2><h3 id=\"4-1-将启动脚本附加到已有容器\"><a href=\"#4-1-将启动脚本附加到已有容器\" class=\"headerlink\" title=\"4.1 将启动脚本附加到已有容器\"></a>4.1 将启动脚本附加到已有容器</h3><p>将脚本复制到容器中 </p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker cp start.sh 容器名称:脚本存储目录<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker cp start.sh awvs-14:/root/<br></code></pre></td></tr></table></figure>\n\n<p>给脚本添加执行权限 </p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker exec 容器名称 chmod +x 脚本路径<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker exec awvs-14 chmod +x /root/start.sh<br></code></pre></td></tr></table></figure>\n\n<p>停止容器</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker stop 容器名称<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker stop awvs-14<br></code></pre></td></tr></table></figure>\n\n<p>将容器提交为新镜像</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker commit 容器名称 镜像名称:tag<br><span class=\"hljs-meta prompt_\"># </span><span class=\"language-bash\">例子</span><br>docker commit awvs-14 awvs:14<br></code></pre></td></tr></table></figure>\n\n<p>以提交的镜像作为基础启动一个新镜像,并以 <code>start.sh</code> 作为启动脚本</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker run -itd --name awvs-14-new awvs:14 /root/start.sh<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"4-2-使用Dockerfile构建并启动\"><a href=\"#4-2-使用Dockerfile构建并启动\" class=\"headerlink\" title=\"4.2 使用Dockerfile构建并启动\"></a>4.2 使用Dockerfile构建并启动</h3><figure class=\"highlight dockerfile\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs dockerfile\"><span class=\"hljs-keyword\">FROM</span> ubuntu:<span class=\"hljs-number\">20.04</span><br><br><span class=\"hljs-keyword\">WORKDIR</span><span class=\"language-bash\"> /root/</span><br><span class=\"hljs-keyword\">COPY</span><span class=\"language-bash\"> start.sh ./</span><br><br><span class=\"hljs-keyword\">RUN</span><span class=\"language-bash\"> <span class=\"hljs-built_in\">chmod</span> +x ./start.sh</span><br><br><span class=\"hljs-keyword\">CMD</span><span class=\"language-bash\"> ./start.sh</span><br></code></pre></td></tr></table></figure>\n\n<p>构建镜像</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker build -t awvs:14 .<br></code></pre></td></tr></table></figure>\n\n<p>以镜像为基础启动容器</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">docker run -itd --name awvs-14-new awvs:14 <br></code></pre></td></tr></table></figure>"},{"title":"个人歌单","index_img":"/images/post/music-cover.jpg","date":"2022-06-17T09:29:47.000Z","_content":"\n<div style=\"display:flex; flex-direction:row; flex-wrap:wrap; justify-content:center;\">\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=29753364&auto=1&height=66\"></iframe>\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1501126567&auto=1&height=66\"></iframe> -->\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1901838921&auto=1&height=66\"></iframe> -->\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298250&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1460946254&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=31421001&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1929285330&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1862798463&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298258&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1340776836&auto=1&height=66\"></iframe>\n</div>","source":"_posts/song-list.md","raw":"---\ntitle: 个人歌单\nindex_img: /images/post/music-cover.jpg\ndate: 2022-06-17 17:29:47\ncategories:\n- 其他\ntags: \n- 网易云\n---\n\n<div style=\"display:flex; flex-direction:row; flex-wrap:wrap; justify-content:center;\">\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=29753364&auto=1&height=66\"></iframe>\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1501126567&auto=1&height=66\"></iframe> -->\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1901838921&auto=1&height=66\"></iframe> -->\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298250&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1460946254&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=31421001&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1929285330&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1862798463&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298258&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1340776836&auto=1&height=66\"></iframe>\n</div>","slug":"song-list","published":1,"updated":"2022-11-02T09:27:34.823Z","_id":"clb4fek6t0007z0iwcu898an8","comments":1,"layout":"post","photos":[],"link":"","content":"<div style=\"display:flex; flex-direction:row; flex-wrap:wrap; justify-content:center;\">\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=29753364&auto=1&height=66\"></iframe>\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1501126567&auto=1&height=66\"></iframe> -->\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1901838921&auto=1&height=66\"></iframe> -->\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298250&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1460946254&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=31421001&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1929285330&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1862798463&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298258&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1340776836&auto=1&height=66\"></iframe>\n</div>","site":{"data":{}},"wordcount":0,"excerpt":"","more":"<div style=\"display:flex; flex-direction:row; flex-wrap:wrap; justify-content:center;\">\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=29753364&auto=1&height=66\"></iframe>\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1501126567&auto=1&height=66\"></iframe> -->\n<!-- <iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1901838921&auto=1&height=66\"></iframe> -->\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298250&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1460946254&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=31421001&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1929285330&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1862798463&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=298258&auto=1&height=66\"></iframe>\n<iframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=330 height=86 src=\"//music.163.com/outchain/player?type=2&id=1340776836&auto=1&height=66\"></iframe>\n</div>"},{"title":"selenium -- 等待网页加载完成","index_img":"/images/post/selenium-cover.jpg","date":"2022-06-17T09:35:12.000Z","_content":"\n\n# selenium -- 等待网页加载完成\n\n使用elenium做项目时候通常需要等待网页完全加载后再执行某些操作\n\n例如需要爬取一个动态表格的数据,需要等待JS完全加载后从后端拿到数据渲染\n\n> 环境:\n> 系统: Windows10\n> Python: Python 3.8.7\n> Selenium: 4.2.0\n\n\n## 1、Selenium等待方式\n\n> 详情请查看官方文档: [https://www.selenium.dev/zh-cn/documentation/webdriver/waits/](https://www.selenium.dev/zh-cn/documentation/webdriver/waits/)\n\n\n### 1.1、显式等待(Explicit wait)\n\n根据等待条件进行等待, 只有等待条件为 `true` 时再继续执行,反正将一直等待直到超时\n\n\n### 1.2、隐式等待(Implicit wait)\n\n全局等待, 只有网页完全加载时才继续执行, 否则将一直等待直到超时\n\n\n### 1.3、流畅等待(Fluent Wait)\n\n多配置版等待,可以配置 最长等待时间, 轮询频率, 忽略等待时出现的特定类型的异常(例如在页面上搜索元素时出现的 `NoSuchElementException` 异常)等\n\n\n\n## 2、等待页面加载完成的方法\n\n### 2.1、使用隐式等待\n\n了解了Selenium的各种等待方法后,很自然地选择了 `隐式等待` ,因为它是全局地,并且会循环检查页面元素是否加载,否则将会一直等待,直到超时或者加载完成\n\n```python\ndriver = Firefox()\n\n# 等待页面加载, 超过10秒抛出异常\ndriver.implicitly_wait(10)\n\n# 后续操作\ndriver.get(\"https://www.baidu.com\")\nmy_dynamic_element = driver.find_element(By.ID, \"myDynamicElement\")\n```\n\n### 2.2、使用显式等待 + JS动态插入元素检查\n\n还有一种方法是利用显式等待配置JS动他插入元素地方式来实现, 原理:\n\n使用JS动态插入一个div元素作为标记元素, 然后使用显式等待, 等待条件为标记元素出现 \n\n```python\nimport uuid\n\n# 为标记元素生成一个UUID\nmarkElementId = uuid.uuid1().hex\n\n# 在Body元素下插入标记元素\njsCode = '''\nlet div = document.createElement('div');\ndiv.setAttribute('id', '@@ID@@');\ndiv.setAttribute('style', 'width: 0px; height: 0px;');\nlet body = document.getElementsByTagName('body')[0];\nbody.appendChild(div);\n'''.replace('@@ID@@', markElementId)\n\n# 等待页面加载完成\ntry:\n # 执行JS\n self.brower.execute_script(jsCode)\n # 如果检测到标注元素, 视为页面加载完成, 否则一直等待, 直到超时\n wait = WebDriverWait(self.brower, 10)\n wait.until(lambda b : b.find_element(By.ID, markElementId))\nexcept Exception as err:\n print('页面加载超时')\n```\n\n","source":"_posts/selenium-waits-for-the-page-to-load.md","raw":"---\ntitle: selenium -- 等待网页加载完成\nindex_img: /images/post/selenium-cover.jpg\ndate: 2022-06-17 17:35:12\ncategories:\n- 开发\n- 爬虫\ntags: \n- selenium\n- 爬虫\n---\n\n\n# selenium -- 等待网页加载完成\n\n使用elenium做项目时候通常需要等待网页完全加载后再执行某些操作\n\n例如需要爬取一个动态表格的数据,需要等待JS完全加载后从后端拿到数据渲染\n\n> 环境:\n> 系统: Windows10\n> Python: Python 3.8.7\n> Selenium: 4.2.0\n\n\n## 1、Selenium等待方式\n\n> 详情请查看官方文档: [https://www.selenium.dev/zh-cn/documentation/webdriver/waits/](https://www.selenium.dev/zh-cn/documentation/webdriver/waits/)\n\n\n### 1.1、显式等待(Explicit wait)\n\n根据等待条件进行等待, 只有等待条件为 `true` 时再继续执行,反正将一直等待直到超时\n\n\n### 1.2、隐式等待(Implicit wait)\n\n全局等待, 只有网页完全加载时才继续执行, 否则将一直等待直到超时\n\n\n### 1.3、流畅等待(Fluent Wait)\n\n多配置版等待,可以配置 最长等待时间, 轮询频率, 忽略等待时出现的特定类型的异常(例如在页面上搜索元素时出现的 `NoSuchElementException` 异常)等\n\n\n\n## 2、等待页面加载完成的方法\n\n### 2.1、使用隐式等待\n\n了解了Selenium的各种等待方法后,很自然地选择了 `隐式等待` ,因为它是全局地,并且会循环检查页面元素是否加载,否则将会一直等待,直到超时或者加载完成\n\n```python\ndriver = Firefox()\n\n# 等待页面加载, 超过10秒抛出异常\ndriver.implicitly_wait(10)\n\n# 后续操作\ndriver.get(\"https://www.baidu.com\")\nmy_dynamic_element = driver.find_element(By.ID, \"myDynamicElement\")\n```\n\n### 2.2、使用显式等待 + JS动态插入元素检查\n\n还有一种方法是利用显式等待配置JS动他插入元素地方式来实现, 原理:\n\n使用JS动态插入一个div元素作为标记元素, 然后使用显式等待, 等待条件为标记元素出现 \n\n```python\nimport uuid\n\n# 为标记元素生成一个UUID\nmarkElementId = uuid.uuid1().hex\n\n# 在Body元素下插入标记元素\njsCode = '''\nlet div = document.createElement('div');\ndiv.setAttribute('id', '@@ID@@');\ndiv.setAttribute('style', 'width: 0px; height: 0px;');\nlet body = document.getElementsByTagName('body')[0];\nbody.appendChild(div);\n'''.replace('@@ID@@', markElementId)\n\n# 等待页面加载完成\ntry:\n # 执行JS\n self.brower.execute_script(jsCode)\n # 如果检测到标注元素, 视为页面加载完成, 否则一直等待, 直到超时\n wait = WebDriverWait(self.brower, 10)\n wait.until(lambda b : b.find_element(By.ID, markElementId))\nexcept Exception as err:\n print('页面加载超时')\n```\n\n","slug":"selenium-waits-for-the-page-to-load","published":1,"updated":"2022-08-16T07:57:54.308Z","_id":"clb4fek6u000az0iw8szb3o5l","comments":1,"layout":"post","photos":[],"link":"","content":"<h1 id=\"selenium-–-等待网页加载完成\"><a href=\"#selenium-–-等待网页加载完成\" class=\"headerlink\" title=\"selenium – 等待网页加载完成\"></a>selenium – 等待网页加载完成</h1><p>使用elenium做项目时候通常需要等待网页完全加载后再执行某些操作</p>\n<p>例如需要爬取一个动态表格的数据,需要等待JS完全加载后从后端拿到数据渲染</p>\n<blockquote>\n<p>环境:<br>系统: Windows10<br>Python: Python 3.8.7<br>Selenium: 4.2.0</p>\n</blockquote>\n<h2 id=\"1、Selenium等待方式\"><a href=\"#1、Selenium等待方式\" class=\"headerlink\" title=\"1、Selenium等待方式\"></a>1、Selenium等待方式</h2><blockquote>\n<p>详情请查看官方文档: <a href=\"https://www.selenium.dev/zh-cn/documentation/webdriver/waits/\">https://www.selenium.dev/zh-cn/documentation/webdriver/waits/</a></p>\n</blockquote>\n<h3 id=\"1-1、显式等待-Explicit-wait\"><a href=\"#1-1、显式等待-Explicit-wait\" class=\"headerlink\" title=\"1.1、显式等待(Explicit wait)\"></a>1.1、显式等待(Explicit wait)</h3><p>根据等待条件进行等待, 只有等待条件为 <code>true</code> 时再继续执行,反正将一直等待直到超时</p>\n<h3 id=\"1-2、隐式等待-Implicit-wait\"><a href=\"#1-2、隐式等待-Implicit-wait\" class=\"headerlink\" title=\"1.2、隐式等待(Implicit wait)\"></a>1.2、隐式等待(Implicit wait)</h3><p>全局等待, 只有网页完全加载时才继续执行, 否则将一直等待直到超时</p>\n<h3 id=\"1-3、流畅等待-Fluent-Wait\"><a href=\"#1-3、流畅等待-Fluent-Wait\" class=\"headerlink\" title=\"1.3、流畅等待(Fluent Wait)\"></a>1.3、流畅等待(Fluent Wait)</h3><p>多配置版等待,可以配置 最长等待时间, 轮询频率, 忽略等待时出现的特定类型的异常(例如在页面上搜索元素时出现的 <code>NoSuchElementException</code> 异常)等</p>\n<h2 id=\"2、等待页面加载完成的方法\"><a href=\"#2、等待页面加载完成的方法\" class=\"headerlink\" title=\"2、等待页面加载完成的方法\"></a>2、等待页面加载完成的方法</h2><h3 id=\"2-1、使用隐式等待\"><a href=\"#2-1、使用隐式等待\" class=\"headerlink\" title=\"2.1、使用隐式等待\"></a>2.1、使用隐式等待</h3><p>了解了Selenium的各种等待方法后,很自然地选择了 <code>隐式等待</code> ,因为它是全局地,并且会循环检查页面元素是否加载,否则将会一直等待,直到超时或者加载完成</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs python\">driver = Firefox()<br><br><span class=\"hljs-comment\"># 等待页面加载, 超过10秒抛出异常</span><br>driver.implicitly_wait(<span class=\"hljs-number\">10</span>)<br><br><span class=\"hljs-comment\"># 后续操作</span><br>driver.get(<span class=\"hljs-string\">"https://www.baidu.com"</span>)<br>my_dynamic_element = driver.find_element(By.ID, <span class=\"hljs-string\">"myDynamicElement"</span>)<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-2、使用显式等待-JS动态插入元素检查\"><a href=\"#2-2、使用显式等待-JS动态插入元素检查\" class=\"headerlink\" title=\"2.2、使用显式等待 + JS动态插入元素检查\"></a>2.2、使用显式等待 + JS动态插入元素检查</h3><p>还有一种方法是利用显式等待配置JS动他插入元素地方式来实现, 原理:</p>\n<p>使用JS动态插入一个div元素作为标记元素, 然后使用显式等待, 等待条件为标记元素出现 </p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs python\"><span class=\"hljs-keyword\">import</span> uuid<br><br><span class=\"hljs-comment\"># 为标记元素生成一个UUID</span><br>markElementId = uuid.uuid1().<span class=\"hljs-built_in\">hex</span><br><br><span class=\"hljs-comment\"># 在Body元素下插入标记元素</span><br>jsCode = <span class=\"hljs-string\">'''</span><br><span class=\"hljs-string\">let div = document.createElement('div');</span><br><span class=\"hljs-string\">div.setAttribute('id', '@@ID@@');</span><br><span class=\"hljs-string\">div.setAttribute('style', 'width: 0px; height: 0px;');</span><br><span class=\"hljs-string\">let body = document.getElementsByTagName('body')[0];</span><br><span class=\"hljs-string\">body.appendChild(div);</span><br><span class=\"hljs-string\">'''</span>.replace(<span class=\"hljs-string\">'@@ID@@'</span>, markElementId)<br><br><span class=\"hljs-comment\"># 等待页面加载完成</span><br><span class=\"hljs-keyword\">try</span>:<br> <span class=\"hljs-comment\"># 执行JS</span><br> self.brower.execute_script(jsCode)<br> <span class=\"hljs-comment\"># 如果检测到标注元素, 视为页面加载完成, 否则一直等待, 直到超时</span><br> wait = WebDriverWait(self.brower, <span class=\"hljs-number\">10</span>)<br> wait.until(<span class=\"hljs-keyword\">lambda</span> b : b.find_element(By.ID, markElementId))<br><span class=\"hljs-keyword\">except</span> Exception <span class=\"hljs-keyword\">as</span> err:<br> <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">'页面加载超时'</span>)<br></code></pre></td></tr></table></figure>\n\n","site":{"data":{}},"wordcount":1477,"excerpt":"","more":"<h1 id=\"selenium-–-等待网页加载完成\"><a href=\"#selenium-–-等待网页加载完成\" class=\"headerlink\" title=\"selenium – 等待网页加载完成\"></a>selenium – 等待网页加载完成</h1><p>使用elenium做项目时候通常需要等待网页完全加载后再执行某些操作</p>\n<p>例如需要爬取一个动态表格的数据,需要等待JS完全加载后从后端拿到数据渲染</p>\n<blockquote>\n<p>环境:<br>系统: Windows10<br>Python: Python 3.8.7<br>Selenium: 4.2.0</p>\n</blockquote>\n<h2 id=\"1、Selenium等待方式\"><a href=\"#1、Selenium等待方式\" class=\"headerlink\" title=\"1、Selenium等待方式\"></a>1、Selenium等待方式</h2><blockquote>\n<p>详情请查看官方文档: <a href=\"https://www.selenium.dev/zh-cn/documentation/webdriver/waits/\">https://www.selenium.dev/zh-cn/documentation/webdriver/waits/</a></p>\n</blockquote>\n<h3 id=\"1-1、显式等待-Explicit-wait\"><a href=\"#1-1、显式等待-Explicit-wait\" class=\"headerlink\" title=\"1.1、显式等待(Explicit wait)\"></a>1.1、显式等待(Explicit wait)</h3><p>根据等待条件进行等待, 只有等待条件为 <code>true</code> 时再继续执行,反正将一直等待直到超时</p>\n<h3 id=\"1-2、隐式等待-Implicit-wait\"><a href=\"#1-2、隐式等待-Implicit-wait\" class=\"headerlink\" title=\"1.2、隐式等待(Implicit wait)\"></a>1.2、隐式等待(Implicit wait)</h3><p>全局等待, 只有网页完全加载时才继续执行, 否则将一直等待直到超时</p>\n<h3 id=\"1-3、流畅等待-Fluent-Wait\"><a href=\"#1-3、流畅等待-Fluent-Wait\" class=\"headerlink\" title=\"1.3、流畅等待(Fluent Wait)\"></a>1.3、流畅等待(Fluent Wait)</h3><p>多配置版等待,可以配置 最长等待时间, 轮询频率, 忽略等待时出现的特定类型的异常(例如在页面上搜索元素时出现的 <code>NoSuchElementException</code> 异常)等</p>\n<h2 id=\"2、等待页面加载完成的方法\"><a href=\"#2、等待页面加载完成的方法\" class=\"headerlink\" title=\"2、等待页面加载完成的方法\"></a>2、等待页面加载完成的方法</h2><h3 id=\"2-1、使用隐式等待\"><a href=\"#2-1、使用隐式等待\" class=\"headerlink\" title=\"2.1、使用隐式等待\"></a>2.1、使用隐式等待</h3><p>了解了Selenium的各种等待方法后,很自然地选择了 <code>隐式等待</code> ,因为它是全局地,并且会循环检查页面元素是否加载,否则将会一直等待,直到超时或者加载完成</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs python\">driver = Firefox()<br><br><span class=\"hljs-comment\"># 等待页面加载, 超过10秒抛出异常</span><br>driver.implicitly_wait(<span class=\"hljs-number\">10</span>)<br><br><span class=\"hljs-comment\"># 后续操作</span><br>driver.get(<span class=\"hljs-string\">"https://www.baidu.com"</span>)<br>my_dynamic_element = driver.find_element(By.ID, <span class=\"hljs-string\">"myDynamicElement"</span>)<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"2-2、使用显式等待-JS动态插入元素检查\"><a href=\"#2-2、使用显式等待-JS动态插入元素检查\" class=\"headerlink\" title=\"2.2、使用显式等待 + JS动态插入元素检查\"></a>2.2、使用显式等待 + JS动态插入元素检查</h3><p>还有一种方法是利用显式等待配置JS动他插入元素地方式来实现, 原理:</p>\n<p>使用JS动态插入一个div元素作为标记元素, 然后使用显式等待, 等待条件为标记元素出现 </p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs python\"><span class=\"hljs-keyword\">import</span> uuid<br><br><span class=\"hljs-comment\"># 为标记元素生成一个UUID</span><br>markElementId = uuid.uuid1().<span class=\"hljs-built_in\">hex</span><br><br><span class=\"hljs-comment\"># 在Body元素下插入标记元素</span><br>jsCode = <span class=\"hljs-string\">'''</span><br><span class=\"hljs-string\">let div = document.createElement('div');</span><br><span class=\"hljs-string\">div.setAttribute('id', '@@ID@@');</span><br><span class=\"hljs-string\">div.setAttribute('style', 'width: 0px; height: 0px;');</span><br><span class=\"hljs-string\">let body = document.getElementsByTagName('body')[0];</span><br><span class=\"hljs-string\">body.appendChild(div);</span><br><span class=\"hljs-string\">'''</span>.replace(<span class=\"hljs-string\">'@@ID@@'</span>, markElementId)<br><br><span class=\"hljs-comment\"># 等待页面加载完成</span><br><span class=\"hljs-keyword\">try</span>:<br> <span class=\"hljs-comment\"># 执行JS</span><br> self.brower.execute_script(jsCode)<br> <span class=\"hljs-comment\"># 如果检测到标注元素, 视为页面加载完成, 否则一直等待, 直到超时</span><br> wait = WebDriverWait(self.brower, <span class=\"hljs-number\">10</span>)<br> wait.until(<span class=\"hljs-keyword\">lambda</span> b : b.find_element(By.ID, markElementId))<br><span class=\"hljs-keyword\">except</span> Exception <span class=\"hljs-keyword\">as</span> err:<br> <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">'页面加载超时'</span>)<br></code></pre></td></tr></table></figure>\n\n"},{"layout":"post","title":"配置ssh免密登录","index_img":"/images/post/ssh-cover.png","date":"2022-11-05T14:54:46.000Z","_content":"\n> **环境**\n> \n> 操作系统:\n> - Windows11: 开发者笔记本(后续使用 `Client` 代替)\n> - Ubuntu Server 20.04: 开发环境(后续使用 `Server` 代替)\n\n> **实现目标**\n>\n> `Client` ssh免密登录 `Server`,免密登录用户为 `mf`\n\n\n## 1、`Client` 创建 ssh 密钥对\n\n启动一个 powershell 并使用以下命令生成密钥对\n\n```shell\nssh-keygen -t rsa\n```\n\n`-t` 参数指定密算法,本例使用 RSA 算法\n\n生成过程中会提示输入 密钥文件名称,如果不指定则使用默认名称 `id_rsa`,存储路径为 `{家目录}/.ssh/id_rsa`\n\n\n```shell\nEnter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa):\n```\n\n不建议使用默认名称,可能会覆盖掉已有的密钥文件\n\n本例将使用 `oksec_development_environment_rsa` 作为密钥文件名称,你可以根据自己的喜好命名任何一个名称\n\n**注意:** 请使用绝对路径指定密钥文件路径\n\n手动输入密钥文件名称后一路回车即可生成一对密钥文件,你可以看到类似以下的输出:\n\n```shell\nPS C:\\Users\\Rebel\\.ssh> ssh-keygen -t rsa \nGenerating public/private rsa key pair.\nEnter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa): C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa\nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.\nYour public key has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.pub.\nThe key fingerprint is:\nSHA256:81v1bxsms7YIJ3omeFyf9q1657U5GOufP+7zjblQnIs rebel@mangfu\nThe key's randomart image is:\n+---[RSA 3072]----+\n| |\n| |\n| |\n| . . |\n| S = |\n| + = o |\n| o .oo.Eo=oo|\n| . +.o+*.**BX|\n| ..+ oo**%&%|\n+----[SHA256]-----+\n```\n\n此时会得到两个密钥文件:\n\n- oksec_development_environment_rsa:私钥文件\n- oksec_development_environment_rsa.pub:公钥文件\n\n\n## 2、将 `Client` 公钥添加到 `Server`\n\n使用用户 `mf` 登录 `Server`\n\n将 `Client` 生成的公钥(也就是 `oksec_development_environment_rsa.pub` 文件的内容)添加到 `Server` 的 `{家目录}/.ssh/authorized_keys` 文件中(如果没有 `authorized_keys` 文件,请创建)\n\n这是本例添加后的结果:\n\n```shell\nmf@mf:~/.ssh$ pwd\n/home/mf/.ssh\nmf@mf:~/.ssh$ cat authorized_keys \nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDL+7Yg4Ztb1AkZ321rXbtP1lBWeJG+LUNFalyE9ElVAQhwNNQLuUuiyHbVuSFQlEGZPyvG4+CtFOVnD2mINZIx7dnOVkhYFyZvq5cMEvzr7gFFDApyvk2roOPkrAskGILtfdIDs30qZTDvrrMGztdcALSK1qhLvj3WAHIhUsjfrlBYR5kts3iVCMwvL/a7J5yIVXUvZe3aNgw83A7vYF3oPoTqdMjJUSbx14kyWQ0Mthc8YfzM1i+EOe3YFwydxpXK5JTVXpgucm0SdFEBevsgWMKguxITN6ELRNBGihhgwQEiiGOnRBFpoXti38gPHoWJXwtOuHrE/lv2DjDqDsyE3jWX6Z6WGSPAZROCxwx7dyP0BGuo2MhTCCiBd2MkQ207ItLu2BqrsS2RUaaZ1OjV5UdOURBe2bxqzxs0toE91qwL9+o3mllWKGD3Rfd1Nl6d5i4u3Ec1UqVtmEvnzfmVaYew/GKtoMfrONYknhkVQqjCwOKd8hya+MyvFOcnIHU= rebel@mangfu\n\nmf@mf:~/.ssh$ \n```\n\n\n\n## 3、`Client` 配置登录\n\n修改 `Client` 的 `{家目录}/.ssh/config` 文件(如果没有请手动创建)\n\n写入以下内容:\n\n```yaml\nHost {连接名称}\n HostName {Server的IP地址}\n PreferredAuthentications publickey\n IdentityFile {Client私钥文件路径}\n User {登录用户}\n```\n\n- {连接名称}:连接名称为 ssh 连接时的名称,可以任意命名,但不建议包含特殊符号\n- {Server的IP地址}:Server的IP地址\n- {Client私钥文件路径}:步骤一中生成的私钥文件的路径\n- {登录用户}:免密登录的用户\n\n以下是本例的配置:\n```yaml\n# 内网开发环境\nHost 公司内网开发环境\n HostName 192.168.0.15\n PreferredAuthentications publickey\n IdentityFile ~/.ssh/oksec_development_environment_rsa\n User mf\n```\n\n\n## 4、测试\n\n在 `Client` 起一个 powershell ,尝试使用 ssh 免密登录 `Server`\n\n```shell\nssh {连接名称}\n```\n\n本例中的连接名称为 `公司内网开发环境`\n\n```\nssh 公司内网开发环境\n```\n\n不出意外的话,你已经成功进入 `Server` 的控制台了\n\n![](images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png)","source":"_posts/配置ssh免密登录.md","raw":"---\nlayout: post\ntitle: 配置ssh免密登录\nindex_img: /images/post/ssh-cover.png\ndate: 2022-11-05 22:54:46\ncategories:\n- 开发\n- 常用配置\ntags:\n- 运维\n- ssh\n---\n\n> **环境**\n> \n> 操作系统:\n> - Windows11: 开发者笔记本(后续使用 `Client` 代替)\n> - Ubuntu Server 20.04: 开发环境(后续使用 `Server` 代替)\n\n> **实现目标**\n>\n> `Client` ssh免密登录 `Server`,免密登录用户为 `mf`\n\n\n## 1、`Client` 创建 ssh 密钥对\n\n启动一个 powershell 并使用以下命令生成密钥对\n\n```shell\nssh-keygen -t rsa\n```\n\n`-t` 参数指定密算法,本例使用 RSA 算法\n\n生成过程中会提示输入 密钥文件名称,如果不指定则使用默认名称 `id_rsa`,存储路径为 `{家目录}/.ssh/id_rsa`\n\n\n```shell\nEnter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa):\n```\n\n不建议使用默认名称,可能会覆盖掉已有的密钥文件\n\n本例将使用 `oksec_development_environment_rsa` 作为密钥文件名称,你可以根据自己的喜好命名任何一个名称\n\n**注意:** 请使用绝对路径指定密钥文件路径\n\n手动输入密钥文件名称后一路回车即可生成一对密钥文件,你可以看到类似以下的输出:\n\n```shell\nPS C:\\Users\\Rebel\\.ssh> ssh-keygen -t rsa \nGenerating public/private rsa key pair.\nEnter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa): C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa\nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.\nYour public key has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.pub.\nThe key fingerprint is:\nSHA256:81v1bxsms7YIJ3omeFyf9q1657U5GOufP+7zjblQnIs rebel@mangfu\nThe key's randomart image is:\n+---[RSA 3072]----+\n| |\n| |\n| |\n| . . |\n| S = |\n| + = o |\n| o .oo.Eo=oo|\n| . +.o+*.**BX|\n| ..+ oo**%&%|\n+----[SHA256]-----+\n```\n\n此时会得到两个密钥文件:\n\n- oksec_development_environment_rsa:私钥文件\n- oksec_development_environment_rsa.pub:公钥文件\n\n\n## 2、将 `Client` 公钥添加到 `Server`\n\n使用用户 `mf` 登录 `Server`\n\n将 `Client` 生成的公钥(也就是 `oksec_development_environment_rsa.pub` 文件的内容)添加到 `Server` 的 `{家目录}/.ssh/authorized_keys` 文件中(如果没有 `authorized_keys` 文件,请创建)\n\n这是本例添加后的结果:\n\n```shell\nmf@mf:~/.ssh$ pwd\n/home/mf/.ssh\nmf@mf:~/.ssh$ cat authorized_keys \nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDL+7Yg4Ztb1AkZ321rXbtP1lBWeJG+LUNFalyE9ElVAQhwNNQLuUuiyHbVuSFQlEGZPyvG4+CtFOVnD2mINZIx7dnOVkhYFyZvq5cMEvzr7gFFDApyvk2roOPkrAskGILtfdIDs30qZTDvrrMGztdcALSK1qhLvj3WAHIhUsjfrlBYR5kts3iVCMwvL/a7J5yIVXUvZe3aNgw83A7vYF3oPoTqdMjJUSbx14kyWQ0Mthc8YfzM1i+EOe3YFwydxpXK5JTVXpgucm0SdFEBevsgWMKguxITN6ELRNBGihhgwQEiiGOnRBFpoXti38gPHoWJXwtOuHrE/lv2DjDqDsyE3jWX6Z6WGSPAZROCxwx7dyP0BGuo2MhTCCiBd2MkQ207ItLu2BqrsS2RUaaZ1OjV5UdOURBe2bxqzxs0toE91qwL9+o3mllWKGD3Rfd1Nl6d5i4u3Ec1UqVtmEvnzfmVaYew/GKtoMfrONYknhkVQqjCwOKd8hya+MyvFOcnIHU= rebel@mangfu\n\nmf@mf:~/.ssh$ \n```\n\n\n\n## 3、`Client` 配置登录\n\n修改 `Client` 的 `{家目录}/.ssh/config` 文件(如果没有请手动创建)\n\n写入以下内容:\n\n```yaml\nHost {连接名称}\n HostName {Server的IP地址}\n PreferredAuthentications publickey\n IdentityFile {Client私钥文件路径}\n User {登录用户}\n```\n\n- {连接名称}:连接名称为 ssh 连接时的名称,可以任意命名,但不建议包含特殊符号\n- {Server的IP地址}:Server的IP地址\n- {Client私钥文件路径}:步骤一中生成的私钥文件的路径\n- {登录用户}:免密登录的用户\n\n以下是本例的配置:\n```yaml\n# 内网开发环境\nHost 公司内网开发环境\n HostName 192.168.0.15\n PreferredAuthentications publickey\n IdentityFile ~/.ssh/oksec_development_environment_rsa\n User mf\n```\n\n\n## 4、测试\n\n在 `Client` 起一个 powershell ,尝试使用 ssh 免密登录 `Server`\n\n```shell\nssh {连接名称}\n```\n\n本例中的连接名称为 `公司内网开发环境`\n\n```\nssh 公司内网开发环境\n```\n\n不出意外的话,你已经成功进入 `Server` 的控制台了\n\n![](images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png)","slug":"配置ssh免密登录","published":1,"updated":"2022-12-25T14:15:44.481Z","_id":"clb4fek6v000bz0iwbbifdamq","comments":1,"photos":[],"link":"","content":"<blockquote>\n<p><strong>环境</strong></p>\n<p>操作系统:</p>\n<ul>\n<li>Windows11: 开发者笔记本(后续使用 <code>Client</code> 代替)</li>\n<li>Ubuntu Server 20.04: 开发环境(后续使用 <code>Server</code> 代替)</li>\n</ul>\n</blockquote>\n<blockquote>\n<p><strong>实现目标</strong></p>\n<p><code>Client</code> ssh免密登录 <code>Server</code>,免密登录用户为 <code>mf</code></p>\n</blockquote>\n<h2 id=\"1、Client-创建-ssh-密钥对\"><a href=\"#1、Client-创建-ssh-密钥对\" class=\"headerlink\" title=\"1、Client 创建 ssh 密钥对\"></a>1、<code>Client</code> 创建 ssh 密钥对</h2><p>启动一个 powershell 并使用以下命令生成密钥对</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">ssh-keygen -t rsa<br></code></pre></td></tr></table></figure>\n\n<p><code>-t</code> 参数指定密算法,本例使用 RSA 算法</p>\n<p>生成过程中会提示输入 密钥文件名称,如果不指定则使用默认名称 <code>id_rsa</code>,存储路径为 <code>{家目录}/.ssh/id_rsa</code></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">Enter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa):<br></code></pre></td></tr></table></figure>\n\n<p>不建议使用默认名称,可能会覆盖掉已有的密钥文件</p>\n<p>本例将使用 <code>oksec_development_environment_rsa</code> 作为密钥文件名称,你可以根据自己的喜好命名任何一个名称</p>\n<p><strong>注意:</strong> 请使用绝对路径指定密钥文件路径</p>\n<p>手动输入密钥文件名称后一路回车即可生成一对密钥文件,你可以看到类似以下的输出:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">PS C:\\Users\\Rebel\\.ssh> ssh-keygen -t rsa <br>Generating public/private rsa key pair.<br>Enter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa): C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa<br>Enter passphrase (empty for no passphrase): <br>Enter same passphrase again: <br>Your identification has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.<br>Your public key has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.pub.<br>The key fingerprint is:<br>SHA256:81v1bxsms7YIJ3omeFyf9q1657U5GOufP+7zjblQnIs rebel@mangfu<br>The key's randomart image is:<br>+---[RSA 3072]----+<br>| |<br>| |<br>| |<br>| . . |<br>| S = |<br>| + = o |<br>| o .oo.Eo=oo|<br>| . +.o+*.**BX|<br>| ..+ oo**%&%|<br>+----[SHA256]-----+<br></code></pre></td></tr></table></figure>\n\n<p>此时会得到两个密钥文件:</p>\n<ul>\n<li>oksec_development_environment_rsa:私钥文件</li>\n<li>oksec_development_environment_rsa.pub:公钥文件</li>\n</ul>\n<h2 id=\"2、将-Client-公钥添加到-Server\"><a href=\"#2、将-Client-公钥添加到-Server\" class=\"headerlink\" title=\"2、将 Client 公钥添加到 Server\"></a>2、将 <code>Client</code> 公钥添加到 <code>Server</code></h2><p>使用用户 <code>mf</code> 登录 <code>Server</code></p>\n<p>将 <code>Client</code> 生成的公钥(也就是 <code>oksec_development_environment_rsa.pub</code> 文件的内容)添加到 <code>Server</code> 的 <code>{家目录}/.ssh/authorized_keys</code> 文件中(如果没有 <code>authorized_keys</code> 文件,请创建)</p>\n<p>这是本例添加后的结果:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">mf@mf:~/.ssh$ pwd<br>/home/mf/.ssh<br>mf@mf:~/.ssh$ cat authorized_keys <br>ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDL+7Yg4Ztb1AkZ321rXbtP1lBWeJG+LUNFalyE9ElVAQhwNNQLuUuiyHbVuSFQlEGZPyvG4+CtFOVnD2mINZIx7dnOVkhYFyZvq5cMEvzr7gFFDApyvk2roOPkrAskGILtfdIDs30qZTDvrrMGztdcALSK1qhLvj3WAHIhUsjfrlBYR5kts3iVCMwvL/a7J5yIVXUvZe3aNgw83A7vYF3oPoTqdMjJUSbx14kyWQ0Mthc8YfzM1i+EOe3YFwydxpXK5JTVXpgucm0SdFEBevsgWMKguxITN6ELRNBGihhgwQEiiGOnRBFpoXti38gPHoWJXwtOuHrE/lv2DjDqDsyE3jWX6Z6WGSPAZROCxwx7dyP0BGuo2MhTCCiBd2MkQ207ItLu2BqrsS2RUaaZ1OjV5UdOURBe2bxqzxs0toE91qwL9+o3mllWKGD3Rfd1Nl6d5i4u3Ec1UqVtmEvnzfmVaYew/GKtoMfrONYknhkVQqjCwOKd8hya+MyvFOcnIHU= rebel@mangfu<br><br>mf@mf:~/.ssh$ <br></code></pre></td></tr></table></figure>\n\n\n\n<h2 id=\"3、Client-配置登录\"><a href=\"#3、Client-配置登录\" class=\"headerlink\" title=\"3、Client 配置登录\"></a>3、<code>Client</code> 配置登录</h2><p>修改 <code>Client</code> 的 <code>{家目录}/.ssh/config</code> 文件(如果没有请手动创建)</p>\n<p>写入以下内容:</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs yaml\"><span class=\"hljs-string\">Host</span> {<span class=\"hljs-string\">连接名称</span>}<br> <span class=\"hljs-string\">HostName</span> {<span class=\"hljs-string\">Server的IP地址</span>}<br> <span class=\"hljs-string\">PreferredAuthentications</span> <span class=\"hljs-string\">publickey</span><br> <span class=\"hljs-string\">IdentityFile</span> {<span class=\"hljs-string\">Client私钥文件路径</span>}<br> <span class=\"hljs-string\">User</span> {<span class=\"hljs-string\">登录用户</span>}<br></code></pre></td></tr></table></figure>\n\n<ul>\n<li>{连接名称}:连接名称为 ssh 连接时的名称,可以任意命名,但不建议包含特殊符号</li>\n<li>{Server的IP地址}:Server的IP地址</li>\n<li>{Client私钥文件路径}:步骤一中生成的私钥文件的路径</li>\n<li>{登录用户}:免密登录的用户</li>\n</ul>\n<p>以下是本例的配置:</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs yaml\"><span class=\"hljs-comment\"># 内网开发环境</span><br><span class=\"hljs-string\">Host</span> <span class=\"hljs-string\">公司内网开发环境</span><br> <span class=\"hljs-string\">HostName</span> <span class=\"hljs-number\">192.168</span><span class=\"hljs-number\">.0</span><span class=\"hljs-number\">.15</span><br> <span class=\"hljs-string\">PreferredAuthentications</span> <span class=\"hljs-string\">publickey</span><br> <span class=\"hljs-string\">IdentityFile</span> <span class=\"hljs-string\">~/.ssh/oksec_development_environment_rsa</span><br> <span class=\"hljs-string\">User</span> <span class=\"hljs-string\">mf</span><br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"4、测试\"><a href=\"#4、测试\" class=\"headerlink\" title=\"4、测试\"></a>4、测试</h2><p>在 <code>Client</code> 起一个 powershell ,尝试使用 ssh 免密登录 <code>Server</code></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">ssh {连接名称}<br></code></pre></td></tr></table></figure>\n\n<p>本例中的连接名称为 <code>公司内网开发环境</code></p>\n<figure class=\"highlight nginx\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs nginx\"><span class=\"hljs-attribute\">ssh</span> 公司内网开发环境<br></code></pre></td></tr></table></figure>\n\n<p>不出意外的话,你已经成功进入 <code>Server</code> 的控制台了</p>\n<p><img src=\"/images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png\"></p>\n","site":{"data":{}},"wordcount":2610,"excerpt":"","more":"<blockquote>\n<p><strong>环境</strong></p>\n<p>操作系统:</p>\n<ul>\n<li>Windows11: 开发者笔记本(后续使用 <code>Client</code> 代替)</li>\n<li>Ubuntu Server 20.04: 开发环境(后续使用 <code>Server</code> 代替)</li>\n</ul>\n</blockquote>\n<blockquote>\n<p><strong>实现目标</strong></p>\n<p><code>Client</code> ssh免密登录 <code>Server</code>,免密登录用户为 <code>mf</code></p>\n</blockquote>\n<h2 id=\"1、Client-创建-ssh-密钥对\"><a href=\"#1、Client-创建-ssh-密钥对\" class=\"headerlink\" title=\"1、Client 创建 ssh 密钥对\"></a>1、<code>Client</code> 创建 ssh 密钥对</h2><p>启动一个 powershell 并使用以下命令生成密钥对</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">ssh-keygen -t rsa<br></code></pre></td></tr></table></figure>\n\n<p><code>-t</code> 参数指定密算法,本例使用 RSA 算法</p>\n<p>生成过程中会提示输入 密钥文件名称,如果不指定则使用默认名称 <code>id_rsa</code>,存储路径为 <code>{家目录}/.ssh/id_rsa</code></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">Enter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa):<br></code></pre></td></tr></table></figure>\n\n<p>不建议使用默认名称,可能会覆盖掉已有的密钥文件</p>\n<p>本例将使用 <code>oksec_development_environment_rsa</code> 作为密钥文件名称,你可以根据自己的喜好命名任何一个名称</p>\n<p><strong>注意:</strong> 请使用绝对路径指定密钥文件路径</p>\n<p>手动输入密钥文件名称后一路回车即可生成一对密钥文件,你可以看到类似以下的输出:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">PS C:\\Users\\Rebel\\.ssh> ssh-keygen -t rsa <br>Generating public/private rsa key pair.<br>Enter file in which to save the key (C:\\Users\\Rebel/.ssh/id_rsa): C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa<br>Enter passphrase (empty for no passphrase): <br>Enter same passphrase again: <br>Your identification has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.<br>Your public key has been saved in C:\\Users\\Rebel/.ssh/oksec_development_environment_rsa.pub.<br>The key fingerprint is:<br>SHA256:81v1bxsms7YIJ3omeFyf9q1657U5GOufP+7zjblQnIs rebel@mangfu<br>The key's randomart image is:<br>+---[RSA 3072]----+<br>| |<br>| |<br>| |<br>| . . |<br>| S = |<br>| + = o |<br>| o .oo.Eo=oo|<br>| . +.o+*.**BX|<br>| ..+ oo**%&%|<br>+----[SHA256]-----+<br></code></pre></td></tr></table></figure>\n\n<p>此时会得到两个密钥文件:</p>\n<ul>\n<li>oksec_development_environment_rsa:私钥文件</li>\n<li>oksec_development_environment_rsa.pub:公钥文件</li>\n</ul>\n<h2 id=\"2、将-Client-公钥添加到-Server\"><a href=\"#2、将-Client-公钥添加到-Server\" class=\"headerlink\" title=\"2、将 Client 公钥添加到 Server\"></a>2、将 <code>Client</code> 公钥添加到 <code>Server</code></h2><p>使用用户 <code>mf</code> 登录 <code>Server</code></p>\n<p>将 <code>Client</code> 生成的公钥(也就是 <code>oksec_development_environment_rsa.pub</code> 文件的内容)添加到 <code>Server</code> 的 <code>{家目录}/.ssh/authorized_keys</code> 文件中(如果没有 <code>authorized_keys</code> 文件,请创建)</p>\n<p>这是本例添加后的结果:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">mf@mf:~/.ssh$ pwd<br>/home/mf/.ssh<br>mf@mf:~/.ssh$ cat authorized_keys <br>ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDL+7Yg4Ztb1AkZ321rXbtP1lBWeJG+LUNFalyE9ElVAQhwNNQLuUuiyHbVuSFQlEGZPyvG4+CtFOVnD2mINZIx7dnOVkhYFyZvq5cMEvzr7gFFDApyvk2roOPkrAskGILtfdIDs30qZTDvrrMGztdcALSK1qhLvj3WAHIhUsjfrlBYR5kts3iVCMwvL/a7J5yIVXUvZe3aNgw83A7vYF3oPoTqdMjJUSbx14kyWQ0Mthc8YfzM1i+EOe3YFwydxpXK5JTVXpgucm0SdFEBevsgWMKguxITN6ELRNBGihhgwQEiiGOnRBFpoXti38gPHoWJXwtOuHrE/lv2DjDqDsyE3jWX6Z6WGSPAZROCxwx7dyP0BGuo2MhTCCiBd2MkQ207ItLu2BqrsS2RUaaZ1OjV5UdOURBe2bxqzxs0toE91qwL9+o3mllWKGD3Rfd1Nl6d5i4u3Ec1UqVtmEvnzfmVaYew/GKtoMfrONYknhkVQqjCwOKd8hya+MyvFOcnIHU= rebel@mangfu<br><br>mf@mf:~/.ssh$ <br></code></pre></td></tr></table></figure>\n\n\n\n<h2 id=\"3、Client-配置登录\"><a href=\"#3、Client-配置登录\" class=\"headerlink\" title=\"3、Client 配置登录\"></a>3、<code>Client</code> 配置登录</h2><p>修改 <code>Client</code> 的 <code>{家目录}/.ssh/config</code> 文件(如果没有请手动创建)</p>\n<p>写入以下内容:</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs yaml\"><span class=\"hljs-string\">Host</span> {<span class=\"hljs-string\">连接名称</span>}<br> <span class=\"hljs-string\">HostName</span> {<span class=\"hljs-string\">Server的IP地址</span>}<br> <span class=\"hljs-string\">PreferredAuthentications</span> <span class=\"hljs-string\">publickey</span><br> <span class=\"hljs-string\">IdentityFile</span> {<span class=\"hljs-string\">Client私钥文件路径</span>}<br> <span class=\"hljs-string\">User</span> {<span class=\"hljs-string\">登录用户</span>}<br></code></pre></td></tr></table></figure>\n\n<ul>\n<li>{连接名称}:连接名称为 ssh 连接时的名称,可以任意命名,但不建议包含特殊符号</li>\n<li>{Server的IP地址}:Server的IP地址</li>\n<li>{Client私钥文件路径}:步骤一中生成的私钥文件的路径</li>\n<li>{登录用户}:免密登录的用户</li>\n</ul>\n<p>以下是本例的配置:</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs yaml\"><span class=\"hljs-comment\"># 内网开发环境</span><br><span class=\"hljs-string\">Host</span> <span class=\"hljs-string\">公司内网开发环境</span><br> <span class=\"hljs-string\">HostName</span> <span class=\"hljs-number\">192.168</span><span class=\"hljs-number\">.0</span><span class=\"hljs-number\">.15</span><br> <span class=\"hljs-string\">PreferredAuthentications</span> <span class=\"hljs-string\">publickey</span><br> <span class=\"hljs-string\">IdentityFile</span> <span class=\"hljs-string\">~/.ssh/oksec_development_environment_rsa</span><br> <span class=\"hljs-string\">User</span> <span class=\"hljs-string\">mf</span><br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"4、测试\"><a href=\"#4、测试\" class=\"headerlink\" title=\"4、测试\"></a>4、测试</h2><p>在 <code>Client</code> 起一个 powershell ,尝试使用 ssh 免密登录 <code>Server</code></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">ssh {连接名称}<br></code></pre></td></tr></table></figure>\n\n<p>本例中的连接名称为 <code>公司内网开发环境</code></p>\n<figure class=\"highlight nginx\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs nginx\"><span class=\"hljs-attribute\">ssh</span> 公司内网开发环境<br></code></pre></td></tr></table></figure>\n\n<p>不出意外的话,你已经成功进入 <code>Server</code> 的控制台了</p>\n<p><img src=\"/images/post/335ef5dc5d2211ed9c9b9335f43ccaf2.png\"></p>\n"},{"layout":"post","title":"网站/在线工具","index_img":"/images/post/navigation-cover.png","date":"2022-11-03T02:09:30.000Z","_content":"\n## 工具相关\n\n### 建设\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://assets.vercel.com/image/upload/front/favicon/vercel/57x57.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>Vercel</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 一个免费网站托管服务,类似于github page,但远比github page强大,速度也快得多得多。不仅仅可以部署静态网站,也可以部署动态网站,与 github 配合还可以达到优雅的发布体验(推送即更新),本博客也使用 Vercel + Github 方式托管\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://vercel.com/'\"\n >访问</div>\n </div>\n</div>\n\n\n### 在线工具\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://baimiao.uzero.cn/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>白描</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 像猫一样灵动的OCR扫描识别神器。具备高准确度的文字识别、表格识别转Excel、批量识别、识别后翻译、文件扫描等功能。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://baimiao.uzero.cn'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.remove.bg/apple-touch-icon.png?v=YAXaAv7pao\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>removebg</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 强大的背景去除工具\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.remove.bg/zh'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://htmlcolorcodes.com/assets/images/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HTML Color Codes</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 个人非常喜欢的一款在线取色/配色工具,另外提供一些网页配色教程\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://htmlcolorcodes.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>临时邮箱</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 在线免费临时邮箱,随用随弃\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.suiyongsuiqi.com/zh/mail/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <!-- <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\"> -->\n <div style=\"width: 80px; height: 80px; line-height: 80px; text-align: center; font-size: 2.5em; border-radius: 50%; background-color: #FFFFFF;\">L</div>\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>LBS数据仓库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 提供 基站,WIFI,LBS定位 \n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='http://www.cellocation.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://command-not-found.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>command-not-found.com</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n \"command not found\", 这句提示语会让多少 Linux 用户感到烦躁,当找不到命令时,你可以尝试使用 command-not-found.com 搜索解决方法,\n 该网站会告诉你在各种 Linux 发行版下安装你需要的 Linux 命令\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://command-not-found.com/'\"\n >访问</div>\n </div>\n</div>\n\n### API\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://api.vvhan.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>韩小韩API接口站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.vvhan.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.free-api.com/image/logo.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>FREE API</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.free-api.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://cdn.wpon.cn/aa1api/img/630f01a3755aa.webp\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HEO</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.aa1.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.showdoc.com.cn/static/logo/w_64.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>showdoc推送服务</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n showdoc官方免费提供的微信通知推送服务,实时推送消息到手机微信,可用于服务器告警、程序监控通知等场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://push.showdoc.com.cn/'\"\n >访问</div>\n </div>\n</div>\n\n## 内容相关\n\n### 图标库\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>iconfont-阿里巴巴矢量图标库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里妈妈MUX倾力打造的矢量图标管理、交流平台,设计师将图标上传到 iconfont 平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师自由调整与调用。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.iconfont.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://lf1-cdn2-tos.bytegoofy.com/bydesign/iconparksite/logo.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>IconPark</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n IconPark 图标库是一个致力于构建高质量、统一化、可定义图标,通过技术驱动矢量图标样式的图标库产品,可以实现根据单—SVG源文件变换出多种主题,具备丰富的分类、更轻量的代码和更灵活的使用场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://iconpark.oceanengine.com/home'\"\n >访问</div>\n </div>\n</div>\n\n\n### 镜像站\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>阿里巴巴开源镜像站-OPSX镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里巴巴开源镜像站,免费提供Linux镜像下载服务,拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源,此外还提供域名解析DNS、网络授时NTP等服务,致力于为互联网用户提供全面,高效和稳定的基础服务。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://developer.aliyun.com/mirror/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://mirrors.tuna.tsinghua.edu.cn/static/img/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>清华大学开源软件镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 与阿里巴巴开源镜像站性质一样,由清华大学 TUNA 协会运行维护。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://mirrors.tuna.tsinghua.edu.cn/'\"\n >访问</div>\n </div>\n</div>\n","source":"_posts/网站或工具.md","raw":"---\nlayout: post\ntitle: 网站/在线工具\nindex_img: /images/post/navigation-cover.png\ndate: 2022-11-03 10:09:30\ncategories:\n- 其他\ntags: \n- 收藏\n- 网站\n- 工具\n---\n\n## 工具相关\n\n### 建设\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://assets.vercel.com/image/upload/front/favicon/vercel/57x57.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>Vercel</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 一个免费网站托管服务,类似于github page,但远比github page强大,速度也快得多得多。不仅仅可以部署静态网站,也可以部署动态网站,与 github 配合还可以达到优雅的发布体验(推送即更新),本博客也使用 Vercel + Github 方式托管\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://vercel.com/'\"\n >访问</div>\n </div>\n</div>\n\n\n### 在线工具\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://baimiao.uzero.cn/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>白描</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 像猫一样灵动的OCR扫描识别神器。具备高准确度的文字识别、表格识别转Excel、批量识别、识别后翻译、文件扫描等功能。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://baimiao.uzero.cn'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.remove.bg/apple-touch-icon.png?v=YAXaAv7pao\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>removebg</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 强大的背景去除工具\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.remove.bg/zh'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://htmlcolorcodes.com/assets/images/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HTML Color Codes</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 个人非常喜欢的一款在线取色/配色工具,另外提供一些网页配色教程\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://htmlcolorcodes.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>临时邮箱</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 在线免费临时邮箱,随用随弃\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.suiyongsuiqi.com/zh/mail/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <!-- <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\"> -->\n <div style=\"width: 80px; height: 80px; line-height: 80px; text-align: center; font-size: 2.5em; border-radius: 50%; background-color: #FFFFFF;\">L</div>\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>LBS数据仓库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 提供 基站,WIFI,LBS定位 \n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='http://www.cellocation.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://command-not-found.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>command-not-found.com</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n \"command not found\", 这句提示语会让多少 Linux 用户感到烦躁,当找不到命令时,你可以尝试使用 command-not-found.com 搜索解决方法,\n 该网站会告诉你在各种 Linux 发行版下安装你需要的 Linux 命令\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://command-not-found.com/'\"\n >访问</div>\n </div>\n</div>\n\n### API\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://api.vvhan.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>韩小韩API接口站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.vvhan.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.free-api.com/image/logo.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>FREE API</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.free-api.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://cdn.wpon.cn/aa1api/img/630f01a3755aa.webp\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HEO</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.aa1.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.showdoc.com.cn/static/logo/w_64.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>showdoc推送服务</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n showdoc官方免费提供的微信通知推送服务,实时推送消息到手机微信,可用于服务器告警、程序监控通知等场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://push.showdoc.com.cn/'\"\n >访问</div>\n </div>\n</div>\n\n## 内容相关\n\n### 图标库\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>iconfont-阿里巴巴矢量图标库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里妈妈MUX倾力打造的矢量图标管理、交流平台,设计师将图标上传到 iconfont 平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师自由调整与调用。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.iconfont.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://lf1-cdn2-tos.bytegoofy.com/bydesign/iconparksite/logo.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>IconPark</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n IconPark 图标库是一个致力于构建高质量、统一化、可定义图标,通过技术驱动矢量图标样式的图标库产品,可以实现根据单—SVG源文件变换出多种主题,具备丰富的分类、更轻量的代码和更灵活的使用场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://iconpark.oceanengine.com/home'\"\n >访问</div>\n </div>\n</div>\n\n\n### 镜像站\n\n<div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>阿里巴巴开源镜像站-OPSX镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里巴巴开源镜像站,免费提供Linux镜像下载服务,拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源,此外还提供域名解析DNS、网络授时NTP等服务,致力于为互联网用户提供全面,高效和稳定的基础服务。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://developer.aliyun.com/mirror/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://mirrors.tuna.tsinghua.edu.cn/static/img/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>清华大学开源软件镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 与阿里巴巴开源镜像站性质一样,由清华大学 TUNA 协会运行维护。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://mirrors.tuna.tsinghua.edu.cn/'\"\n >访问</div>\n </div>\n</div>\n","slug":"网站或工具","published":1,"updated":"2022-12-25T14:15:44.481Z","_id":"clb4fek6x000ez0iwdsee9z80","comments":1,"photos":[],"link":"","content":"<h2 id=\"工具相关\"><a href=\"#工具相关\" class=\"headerlink\" title=\"工具相关\"></a>工具相关</h2><h3 id=\"建设\"><a href=\"#建设\" class=\"headerlink\" title=\"建设\"></a>建设</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://assets.vercel.com/image/upload/front/favicon/vercel/57x57.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>Vercel</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 一个免费网站托管服务,类似于github page,但远比github page强大,速度也快得多得多。不仅仅可以部署静态网站,也可以部署动态网站,与 github 配合还可以达到优雅的发布体验(推送即更新),本博客也使用 Vercel + Github 方式托管\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://vercel.com/'\"\n >访问</div>\n </div>\n</div>\n\n\n<h3 id=\"在线工具\"><a href=\"#在线工具\" class=\"headerlink\" title=\"在线工具\"></a>在线工具</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://baimiao.uzero.cn/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>白描</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 像猫一样灵动的OCR扫描识别神器。具备高准确度的文字识别、表格识别转Excel、批量识别、识别后翻译、文件扫描等功能。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://baimiao.uzero.cn'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.remove.bg/apple-touch-icon.png?v=YAXaAv7pao\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>removebg</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 强大的背景去除工具\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.remove.bg/zh'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://htmlcolorcodes.com/assets/images/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HTML Color Codes</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 个人非常喜欢的一款在线取色/配色工具,另外提供一些网页配色教程\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://htmlcolorcodes.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>临时邮箱</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 在线免费临时邮箱,随用随弃\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.suiyongsuiqi.com/zh/mail/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <!-- <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\"> -->\n <div style=\"width: 80px; height: 80px; line-height: 80px; text-align: center; font-size: 2.5em; border-radius: 50%; background-color: #FFFFFF;\">L</div>\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>LBS数据仓库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 提供 基站,WIFI,LBS定位 \n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='http://www.cellocation.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://command-not-found.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>command-not-found.com</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n \"command not found\", 这句提示语会让多少 Linux 用户感到烦躁,当找不到命令时,你可以尝试使用 command-not-found.com 搜索解决方法,\n 该网站会告诉你在各种 Linux 发行版下安装你需要的 Linux 命令\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://command-not-found.com/'\"\n >访问</div>\n </div>\n</div>\n\n<h3 id=\"API\"><a href=\"#API\" class=\"headerlink\" title=\"API\"></a>API</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://api.vvhan.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>韩小韩API接口站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.vvhan.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.free-api.com/image/logo.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>FREE API</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.free-api.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://cdn.wpon.cn/aa1api/img/630f01a3755aa.webp\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HEO</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.aa1.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.showdoc.com.cn/static/logo/w_64.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>showdoc推送服务</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n showdoc官方免费提供的微信通知推送服务,实时推送消息到手机微信,可用于服务器告警、程序监控通知等场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://push.showdoc.com.cn/'\"\n >访问</div>\n </div>\n</div>\n\n<h2 id=\"内容相关\"><a href=\"#内容相关\" class=\"headerlink\" title=\"内容相关\"></a>内容相关</h2><h3 id=\"图标库\"><a href=\"#图标库\" class=\"headerlink\" title=\"图标库\"></a>图标库</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>iconfont-阿里巴巴矢量图标库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里妈妈MUX倾力打造的矢量图标管理、交流平台,设计师将图标上传到 iconfont 平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师自由调整与调用。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.iconfont.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://lf1-cdn2-tos.bytegoofy.com/bydesign/iconparksite/logo.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>IconPark</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n IconPark 图标库是一个致力于构建高质量、统一化、可定义图标,通过技术驱动矢量图标样式的图标库产品,可以实现根据单—SVG源文件变换出多种主题,具备丰富的分类、更轻量的代码和更灵活的使用场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://iconpark.oceanengine.com/home'\"\n >访问</div>\n </div>\n</div>\n\n\n<h3 id=\"镜像站\"><a href=\"#镜像站\" class=\"headerlink\" title=\"镜像站\"></a>镜像站</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>阿里巴巴开源镜像站-OPSX镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里巴巴开源镜像站,免费提供Linux镜像下载服务,拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源,此外还提供域名解析DNS、网络授时NTP等服务,致力于为互联网用户提供全面,高效和稳定的基础服务。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://developer.aliyun.com/mirror/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://mirrors.tuna.tsinghua.edu.cn/static/img/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>清华大学开源软件镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 与阿里巴巴开源镜像站性质一样,由清华大学 TUNA 协会运行维护。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://mirrors.tuna.tsinghua.edu.cn/'\"\n >访问</div>\n </div>\n</div>\n","site":{"data":{}},"wordcount":987,"excerpt":"","more":"<h2 id=\"工具相关\"><a href=\"#工具相关\" class=\"headerlink\" title=\"工具相关\"></a>工具相关</h2><h3 id=\"建设\"><a href=\"#建设\" class=\"headerlink\" title=\"建设\"></a>建设</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://assets.vercel.com/image/upload/front/favicon/vercel/57x57.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>Vercel</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 一个免费网站托管服务,类似于github page,但远比github page强大,速度也快得多得多。不仅仅可以部署静态网站,也可以部署动态网站,与 github 配合还可以达到优雅的发布体验(推送即更新),本博客也使用 Vercel + Github 方式托管\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://vercel.com/'\"\n >访问</div>\n </div>\n</div>\n\n\n<h3 id=\"在线工具\"><a href=\"#在线工具\" class=\"headerlink\" title=\"在线工具\"></a>在线工具</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://baimiao.uzero.cn/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>白描</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 像猫一样灵动的OCR扫描识别神器。具备高准确度的文字识别、表格识别转Excel、批量识别、识别后翻译、文件扫描等功能。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://baimiao.uzero.cn'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.remove.bg/apple-touch-icon.png?v=YAXaAv7pao\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>removebg</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 强大的背景去除工具\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.remove.bg/zh'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://htmlcolorcodes.com/assets/images/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HTML Color Codes</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 个人非常喜欢的一款在线取色/配色工具,另外提供一些网页配色教程\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://htmlcolorcodes.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>临时邮箱</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 在线免费临时邮箱,随用随弃\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.suiyongsuiqi.com/zh/mail/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <!-- <img style=\"border-radius: 50%;\" src=\"https://www.suiyongsuiqi.com/favicon.ico\" height=\"80\" width=\"80\"> -->\n <div style=\"width: 80px; height: 80px; line-height: 80px; text-align: center; font-size: 2.5em; border-radius: 50%; background-color: #FFFFFF;\">L</div>\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>LBS数据仓库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 提供 基站,WIFI,LBS定位 \n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='http://www.cellocation.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://command-not-found.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>command-not-found.com</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n \"command not found\", 这句提示语会让多少 Linux 用户感到烦躁,当找不到命令时,你可以尝试使用 command-not-found.com 搜索解决方法,\n 该网站会告诉你在各种 Linux 发行版下安装你需要的 Linux 命令\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://command-not-found.com/'\"\n >访问</div>\n </div>\n</div>\n\n<h3 id=\"API\"><a href=\"#API\" class=\"headerlink\" title=\"API\"></a>API</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://api.vvhan.com/favicon.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>韩小韩API接口站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.vvhan.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.free-api.com/image/logo.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>FREE API</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.free-api.com/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://cdn.wpon.cn/aa1api/img/630f01a3755aa.webp\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>HEO</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 免费接口\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://api.aa1.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://www.showdoc.com.cn/static/logo/w_64.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>showdoc推送服务</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n showdoc官方免费提供的微信通知推送服务,实时推送消息到手机微信,可用于服务器告警、程序监控通知等场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://push.showdoc.com.cn/'\"\n >访问</div>\n </div>\n</div>\n\n<h2 id=\"内容相关\"><a href=\"#内容相关\" class=\"headerlink\" title=\"内容相关\"></a>内容相关</h2><h3 id=\"图标库\"><a href=\"#图标库\" class=\"headerlink\" title=\"图标库\"></a>图标库</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>iconfont-阿里巴巴矢量图标库</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里妈妈MUX倾力打造的矢量图标管理、交流平台,设计师将图标上传到 iconfont 平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师自由调整与调用。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://www.iconfont.cn/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://lf1-cdn2-tos.bytegoofy.com/bydesign/iconparksite/logo.svg\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>IconPark</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n IconPark 图标库是一个致力于构建高质量、统一化、可定义图标,通过技术驱动矢量图标样式的图标库产品,可以实现根据单—SVG源文件变换出多种主题,具备丰富的分类、更轻量的代码和更灵活的使用场景\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://iconpark.oceanengine.com/home'\"\n >访问</div>\n </div>\n</div>\n\n\n<h3 id=\"镜像站\"><a href=\"#镜像站\" class=\"headerlink\" title=\"镜像站\"></a>镜像站</h3><div style=\"text-align: left;\">\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>阿里巴巴开源镜像站-OPSX镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 阿里巴巴开源镜像站,免费提供Linux镜像下载服务,拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源,此外还提供域名解析DNS、网络授时NTP等服务,致力于为互联网用户提供全面,高效和稳定的基础服务。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://developer.aliyun.com/mirror/'\"\n >访问</div>\n </div>\n <div style=\"width: 270px; height: 340px; border-radius: 10px; overflow: hidden; display: inline-block; box-shadow: 0px 0px 4px 0px #666666; margin: 10px;\">\n <div style=\"width: 100%; height: 120px; display: flex; justify-content: center; align-items: center;\">\n <img style=\"border-radius: 50%;\" src=\"https://mirrors.tuna.tsinghua.edu.cn/static/img/favicon.png\" height=\"80\" width=\"80\">\n </div>\n <div style=\"width: 100%; height: 40px; text-align: center;\"><strong>清华大学开源软件镜像站</strong></div>\n <div style=\"width: 100%; height: 130px; text-align: left; padding: 10px; font-size: 0.9em; overflow: auto;\">\n 与阿里巴巴开源镜像站性质一样,由清华大学 TUNA 协会运行维护。\n </div>\n <div \n style=\"width: 100%; height: 50px; line-height: 50px; text-align: right; padding-right: 10px; cursor: pointer;\"\n onclick=\"window.location.href='https://mirrors.tuna.tsinghua.edu.cn/'\"\n >访问</div>\n </div>\n</div>\n"},{"layout":"post","title":"搭建私有pypi","index_img":"/images/post/pypi-cover.png","date":"2022-10-29T03:42:41.000Z","_content":"> 环境:\n> 操作系统: ubuntu:20.04\n\n## 1、安装 Python3 + pip\n\n```shell\napt update\napt install -y python3 python3-pip\n```\n\n\n## 2、安装 pypiserver\n\n```shell\npython3 -m pip install pypiserver\n```\n\n如果网络错误,无法访问官方 pypi ,可以使用国内镜像 pypi 站点\n\n例如 阿里云 pypi:[https://mirrors.aliyun.com/pypi/simple/](https://mirrors.aliyun.com/pypi/simple/)\n\n```shell\npython3 -m pip install pypiserver -i https://mirrors.aliyun.com/pypi/simple/\n```\n\n## 3、无认证方式启动\n\n安装完成后可以使用以下命令启动一个无需 用户/密码 认证的 pypi 服务\n```shell\npypi-server\n```\n\npypiserver 默认监听 8080 端口,访问 http://youip:8080 ,如果可以看到欢迎页面,表示服务启动成功\n\n![](images/post/ce25d5b1573d11ed95612cfda1215af5.png)\n\n> 如果你想自定义端口,请使用 -p 参数指定\n\n```shell\npypi-server -p 8000\n```\n\n## 4、带认证方式启动\n\n### 4.1、使用 htpasswd 生成密码文件\n\n> htpasswd 命令是 Apache 的 Web 服务器内置工具,用于创建和更新储存用户名、域和用户基本认证的密码文件。\n\n如果提示命令不存在,使用以下命令安装 htpasswd\n\n```shell\napt install -y apache2-utils\n```\n\n使用以下命令在当前用户家目录生成密码文件 `.pypipasswd`\n认证用户名为 `pypi`\n\n```shell\nhtpasswd -c ~/.pypipasswd pypi\n```\n\n生成过程中提示输入用户密码,请为 `pypi` 用户设置一个访问密码\n```shell\nroot@98fabb4b0b64:~# htpasswd -c ~/.pypipasswd pypi\nNew password: \nRe-type new password: \nAdding password for user pypi\n```\n\n### 4.2、使用密码文件启动带验证的 pypi 服务\n\n```shell\npypi-server -P ~/.pypipasswd \n```\n\n如果报以下错误:\n\n```shell\napache.passlib library is not available. You must install pypiserver with the optional 'passlib' dependency (`pip install pypiserver['passlib']`) in order to use password authentication\n```\n\n执行以下命令安装 `pypiserver['passlib']` 后尝试再次启动 pypi 服务\n\n```shell\npython3 -m pip install pypiserver['passlib']\n```\n","source":"_posts/搭建私有pypi.md","raw":"---\nlayout: post\ntitle: 搭建私有pypi\nindex_img: /images/post/pypi-cover.png\ndate: 2022-10-29 11:42:41\ncategories:\n- 建设\ntags: \n- python\n- pypi\n---\n> 环境:\n> 操作系统: ubuntu:20.04\n\n## 1、安装 Python3 + pip\n\n```shell\napt update\napt install -y python3 python3-pip\n```\n\n\n## 2、安装 pypiserver\n\n```shell\npython3 -m pip install pypiserver\n```\n\n如果网络错误,无法访问官方 pypi ,可以使用国内镜像 pypi 站点\n\n例如 阿里云 pypi:[https://mirrors.aliyun.com/pypi/simple/](https://mirrors.aliyun.com/pypi/simple/)\n\n```shell\npython3 -m pip install pypiserver -i https://mirrors.aliyun.com/pypi/simple/\n```\n\n## 3、无认证方式启动\n\n安装完成后可以使用以下命令启动一个无需 用户/密码 认证的 pypi 服务\n```shell\npypi-server\n```\n\npypiserver 默认监听 8080 端口,访问 http://youip:8080 ,如果可以看到欢迎页面,表示服务启动成功\n\n![](images/post/ce25d5b1573d11ed95612cfda1215af5.png)\n\n> 如果你想自定义端口,请使用 -p 参数指定\n\n```shell\npypi-server -p 8000\n```\n\n## 4、带认证方式启动\n\n### 4.1、使用 htpasswd 生成密码文件\n\n> htpasswd 命令是 Apache 的 Web 服务器内置工具,用于创建和更新储存用户名、域和用户基本认证的密码文件。\n\n如果提示命令不存在,使用以下命令安装 htpasswd\n\n```shell\napt install -y apache2-utils\n```\n\n使用以下命令在当前用户家目录生成密码文件 `.pypipasswd`\n认证用户名为 `pypi`\n\n```shell\nhtpasswd -c ~/.pypipasswd pypi\n```\n\n生成过程中提示输入用户密码,请为 `pypi` 用户设置一个访问密码\n```shell\nroot@98fabb4b0b64:~# htpasswd -c ~/.pypipasswd pypi\nNew password: \nRe-type new password: \nAdding password for user pypi\n```\n\n### 4.2、使用密码文件启动带验证的 pypi 服务\n\n```shell\npypi-server -P ~/.pypipasswd \n```\n\n如果报以下错误:\n\n```shell\napache.passlib library is not available. You must install pypiserver with the optional 'passlib' dependency (`pip install pypiserver['passlib']`) in order to use password authentication\n```\n\n执行以下命令安装 `pypiserver['passlib']` 后尝试再次启动 pypi 服务\n\n```shell\npython3 -m pip install pypiserver['passlib']\n```\n","slug":"搭建私有pypi","published":1,"updated":"2022-10-29T04:19:05.945Z","_id":"clb4fek6y000gz0iw1o0uh2v9","comments":1,"photos":[],"link":"","content":"<blockquote>\n<p>环境:<br>操作系统: ubuntu:20.04</p>\n</blockquote>\n<h2 id=\"1、安装-Python3-pip\"><a href=\"#1、安装-Python3-pip\" class=\"headerlink\" title=\"1、安装 Python3 + pip\"></a>1、安装 Python3 + pip</h2><figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apt update<br>apt install -y python3 python3-pip<br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"2、安装-pypiserver\"><a href=\"#2、安装-pypiserver\" class=\"headerlink\" title=\"2、安装 pypiserver\"></a>2、安装 pypiserver</h2><figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">python3 -m pip install pypiserver<br></code></pre></td></tr></table></figure>\n\n<p>如果网络错误,无法访问官方 pypi ,可以使用国内镜像 pypi 站点</p>\n<p>例如 阿里云 pypi:<a href=\"https://mirrors.aliyun.com/pypi/simple/\">https://mirrors.aliyun.com/pypi/simple/</a></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">python3 -m pip install pypiserver -i https://mirrors.aliyun.com/pypi/simple/<br></code></pre></td></tr></table></figure>\n\n<h2 id=\"3、无认证方式启动\"><a href=\"#3、无认证方式启动\" class=\"headerlink\" title=\"3、无认证方式启动\"></a>3、无认证方式启动</h2><p>安装完成后可以使用以下命令启动一个无需 用户/密码 认证的 pypi 服务</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">pypi-server<br></code></pre></td></tr></table></figure>\n\n<p>pypiserver 默认监听 8080 端口,访问 <a href=\"http://youip:8080/\">http://youip:8080</a> ,如果可以看到欢迎页面,表示服务启动成功</p>\n<p><img src=\"/images/post/ce25d5b1573d11ed95612cfda1215af5.png\"></p>\n<blockquote>\n<p>如果你想自定义端口,请使用 -p 参数指定</p>\n</blockquote>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">pypi-server -p 8000<br></code></pre></td></tr></table></figure>\n\n<h2 id=\"4、带认证方式启动\"><a href=\"#4、带认证方式启动\" class=\"headerlink\" title=\"4、带认证方式启动\"></a>4、带认证方式启动</h2><h3 id=\"4-1、使用-htpasswd-生成密码文件\"><a href=\"#4-1、使用-htpasswd-生成密码文件\" class=\"headerlink\" title=\"4.1、使用 htpasswd 生成密码文件\"></a>4.1、使用 htpasswd 生成密码文件</h3><blockquote>\n<p>htpasswd 命令是 Apache 的 Web 服务器内置工具,用于创建和更新储存用户名、域和用户基本认证的密码文件。</p>\n</blockquote>\n<p>如果提示命令不存在,使用以下命令安装 htpasswd</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apt install -y apache2-utils<br></code></pre></td></tr></table></figure>\n\n<p>使用以下命令在当前用户家目录生成密码文件 <code>.pypipasswd</code><br>认证用户名为 <code>pypi</code></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">htpasswd -c ~/.pypipasswd pypi<br></code></pre></td></tr></table></figure>\n\n<p>生成过程中提示输入用户密码,请为 <code>pypi</code> 用户设置一个访问密码</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">root@98fabb4b0b64:~# htpasswd -c ~/.pypipasswd pypi<br>New password: <br>Re-type new password: <br>Adding password for user pypi<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"4-2、使用密码文件启动带验证的-pypi-服务\"><a href=\"#4-2、使用密码文件启动带验证的-pypi-服务\" class=\"headerlink\" title=\"4.2、使用密码文件启动带验证的 pypi 服务\"></a>4.2、使用密码文件启动带验证的 pypi 服务</h3><figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">pypi-server -P ~/.pypipasswd <br></code></pre></td></tr></table></figure>\n\n<p>如果报以下错误:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apache.passlib library is not available. You must install pypiserver with the optional 'passlib' dependency (`pip install pypiserver['passlib']`) in order to use password authentication<br></code></pre></td></tr></table></figure>\n\n<p>执行以下命令安装 <code>pypiserver['passlib']</code> 后尝试再次启动 pypi 服务</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">python3 -m pip install pypiserver['passlib']<br></code></pre></td></tr></table></figure>\n","site":{"data":{}},"wordcount":1113,"excerpt":"","more":"<blockquote>\n<p>环境:<br>操作系统: ubuntu:20.04</p>\n</blockquote>\n<h2 id=\"1、安装-Python3-pip\"><a href=\"#1、安装-Python3-pip\" class=\"headerlink\" title=\"1、安装 Python3 + pip\"></a>1、安装 Python3 + pip</h2><figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apt update<br>apt install -y python3 python3-pip<br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"2、安装-pypiserver\"><a href=\"#2、安装-pypiserver\" class=\"headerlink\" title=\"2、安装 pypiserver\"></a>2、安装 pypiserver</h2><figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">python3 -m pip install pypiserver<br></code></pre></td></tr></table></figure>\n\n<p>如果网络错误,无法访问官方 pypi ,可以使用国内镜像 pypi 站点</p>\n<p>例如 阿里云 pypi:<a href=\"https://mirrors.aliyun.com/pypi/simple/\">https://mirrors.aliyun.com/pypi/simple/</a></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">python3 -m pip install pypiserver -i https://mirrors.aliyun.com/pypi/simple/<br></code></pre></td></tr></table></figure>\n\n<h2 id=\"3、无认证方式启动\"><a href=\"#3、无认证方式启动\" class=\"headerlink\" title=\"3、无认证方式启动\"></a>3、无认证方式启动</h2><p>安装完成后可以使用以下命令启动一个无需 用户/密码 认证的 pypi 服务</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">pypi-server<br></code></pre></td></tr></table></figure>\n\n<p>pypiserver 默认监听 8080 端口,访问 <a href=\"http://youip:8080/\">http://youip:8080</a> ,如果可以看到欢迎页面,表示服务启动成功</p>\n<p><img src=\"/images/post/ce25d5b1573d11ed95612cfda1215af5.png\"></p>\n<blockquote>\n<p>如果你想自定义端口,请使用 -p 参数指定</p>\n</blockquote>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">pypi-server -p 8000<br></code></pre></td></tr></table></figure>\n\n<h2 id=\"4、带认证方式启动\"><a href=\"#4、带认证方式启动\" class=\"headerlink\" title=\"4、带认证方式启动\"></a>4、带认证方式启动</h2><h3 id=\"4-1、使用-htpasswd-生成密码文件\"><a href=\"#4-1、使用-htpasswd-生成密码文件\" class=\"headerlink\" title=\"4.1、使用 htpasswd 生成密码文件\"></a>4.1、使用 htpasswd 生成密码文件</h3><blockquote>\n<p>htpasswd 命令是 Apache 的 Web 服务器内置工具,用于创建和更新储存用户名、域和用户基本认证的密码文件。</p>\n</blockquote>\n<p>如果提示命令不存在,使用以下命令安装 htpasswd</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apt install -y apache2-utils<br></code></pre></td></tr></table></figure>\n\n<p>使用以下命令在当前用户家目录生成密码文件 <code>.pypipasswd</code><br>认证用户名为 <code>pypi</code></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">htpasswd -c ~/.pypipasswd pypi<br></code></pre></td></tr></table></figure>\n\n<p>生成过程中提示输入用户密码,请为 <code>pypi</code> 用户设置一个访问密码</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">root@98fabb4b0b64:~# htpasswd -c ~/.pypipasswd pypi<br>New password: <br>Re-type new password: <br>Adding password for user pypi<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"4-2、使用密码文件启动带验证的-pypi-服务\"><a href=\"#4-2、使用密码文件启动带验证的-pypi-服务\" class=\"headerlink\" title=\"4.2、使用密码文件启动带验证的 pypi 服务\"></a>4.2、使用密码文件启动带验证的 pypi 服务</h3><figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">pypi-server -P ~/.pypipasswd <br></code></pre></td></tr></table></figure>\n\n<p>如果报以下错误:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">apache.passlib library is not available. You must install pypiserver with the optional 'passlib' dependency (`pip install pypiserver['passlib']`) in order to use password authentication<br></code></pre></td></tr></table></figure>\n\n<p>执行以下命令安装 <code>pypiserver['passlib']</code> 后尝试再次启动 pypi 服务</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs shell\">python3 -m pip install pypiserver['passlib']<br></code></pre></td></tr></table></figure>\n"},{"layout":"post","title":"代码片段","index_img":"/images/post/code-cover.png","date":"2022-11-09T06:29:24.000Z","_content":"\n\n## Git\n\n### 修改 commit 信息\n\n适用于 commit 但还没有 push 的提交\n\n```bash\ngit commit --amend\n```\n\n\n## Docker\n\n### 停止所有容器\n\n```bash\ndocker stop `docker ps --format \"{{.Names}}\"`\n```\n\n### 删除所有容器\n\n删除前需要停止所有容器\n\n```bash\ndocker rm `docker ps --format \"{{.Names}}\"`\n```\n\n\n## Linux \n\n### 查看端口占用\n\n例如查看 `80` 端口占用\n\n```bash\nnetstat -tunlp | grep 80\n```","source":"_posts/代码片段.md","raw":"---\nlayout: post\ntitle: 代码片段\nindex_img: /images/post/code-cover.png\ndate: 2022-11-09 14:29:24\ncategories:\n- 开发\ntags:\n- 代码片段\n- Linux\n- Python\n- Git\n---\n\n\n## Git\n\n### 修改 commit 信息\n\n适用于 commit 但还没有 push 的提交\n\n```bash\ngit commit --amend\n```\n\n\n## Docker\n\n### 停止所有容器\n\n```bash\ndocker stop `docker ps --format \"{{.Names}}\"`\n```\n\n### 删除所有容器\n\n删除前需要停止所有容器\n\n```bash\ndocker rm `docker ps --format \"{{.Names}}\"`\n```\n\n\n## Linux \n\n### 查看端口占用\n\n例如查看 `80` 端口占用\n\n```bash\nnetstat -tunlp | grep 80\n```","slug":"代码片段","published":1,"updated":"2022-12-25T14:15:44.481Z","_id":"clb4fek70000lz0iw9tba4mwz","comments":1,"photos":[],"link":"","content":"<h2 id=\"Git\"><a href=\"#Git\" class=\"headerlink\" title=\"Git\"></a>Git</h2><h3 id=\"修改-commit-信息\"><a href=\"#修改-commit-信息\" class=\"headerlink\" title=\"修改 commit 信息\"></a>修改 commit 信息</h3><p>适用于 commit 但还没有 push 的提交</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">git commit --amend<br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"Docker\"><a href=\"#Docker\" class=\"headerlink\" title=\"Docker\"></a>Docker</h2><h3 id=\"停止所有容器\"><a href=\"#停止所有容器\" class=\"headerlink\" title=\"停止所有容器\"></a>停止所有容器</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">docker stop `docker ps --format <span class=\"hljs-string\">"{{.Names}}"</span>`<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"删除所有容器\"><a href=\"#删除所有容器\" class=\"headerlink\" title=\"删除所有容器\"></a>删除所有容器</h3><p>删除前需要停止所有容器</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">docker <span class=\"hljs-built_in\">rm</span> `docker ps --format <span class=\"hljs-string\">"{{.Names}}"</span>`<br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"Linux\"><a href=\"#Linux\" class=\"headerlink\" title=\"Linux\"></a>Linux</h2><h3 id=\"查看端口占用\"><a href=\"#查看端口占用\" class=\"headerlink\" title=\"查看端口占用\"></a>查看端口占用</h3><p>例如查看 <code>80</code> 端口占用</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">netstat -tunlp | grep 80<br></code></pre></td></tr></table></figure>","site":{"data":{}},"wordcount":261,"excerpt":"","more":"<h2 id=\"Git\"><a href=\"#Git\" class=\"headerlink\" title=\"Git\"></a>Git</h2><h3 id=\"修改-commit-信息\"><a href=\"#修改-commit-信息\" class=\"headerlink\" title=\"修改 commit 信息\"></a>修改 commit 信息</h3><p>适用于 commit 但还没有 push 的提交</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">git commit --amend<br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"Docker\"><a href=\"#Docker\" class=\"headerlink\" title=\"Docker\"></a>Docker</h2><h3 id=\"停止所有容器\"><a href=\"#停止所有容器\" class=\"headerlink\" title=\"停止所有容器\"></a>停止所有容器</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">docker stop `docker ps --format <span class=\"hljs-string\">"{{.Names}}"</span>`<br></code></pre></td></tr></table></figure>\n\n<h3 id=\"删除所有容器\"><a href=\"#删除所有容器\" class=\"headerlink\" title=\"删除所有容器\"></a>删除所有容器</h3><p>删除前需要停止所有容器</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">docker <span class=\"hljs-built_in\">rm</span> `docker ps --format <span class=\"hljs-string\">"{{.Names}}"</span>`<br></code></pre></td></tr></table></figure>\n\n\n<h2 id=\"Linux\"><a href=\"#Linux\" class=\"headerlink\" title=\"Linux\"></a>Linux</h2><h3 id=\"查看端口占用\"><a href=\"#查看端口占用\" class=\"headerlink\" title=\"查看端口占用\"></a>查看端口占用</h3><p>例如查看 <code>80</code> 端口占用</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><code class=\"hljs bash\">netstat -tunlp | grep 80<br></code></pre></td></tr></table></figure>"}],"PostAsset":[],"PostCategory":[{"post_id":"clb4fek6l0002z0iwe86z0b68","category_id":"clb4fek6u0008z0iwejz34cu2","_id":"clb4fek6z000iz0iwhb8q6yqx"},{"post_id":"clb4fek6s0006z0iw11hdcegc","category_id":"clb4fek6w000cz0iw4qrz1yb8","_id":"clb4fek72000nz0iw3dkyh6qz"},{"post_id":"clb4fek6y000gz0iw1o0uh2v9","category_id":"clb4fek6u0008z0iwejz34cu2","_id":"clb4fek73000qz0iwa4tg40j1"},{"post_id":"clb4fek70000lz0iw9tba4mwz","category_id":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek73000rz0iwevvzetxp"},{"post_id":"clb4fek6t0007z0iwcu898an8","category_id":"clb4fek73000pz0iwfg1k64ky","_id":"clb4fek74000wz0iw2hkxf32u"},{"post_id":"clb4fek6u000az0iw8szb3o5l","category_id":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek740010z0iw3pymae3u"},{"post_id":"clb4fek6u000az0iw8szb3o5l","category_id":"clb4fek74000tz0iw6xqab26v","_id":"clb4fek750013z0iwa766gh1g"},{"post_id":"clb4fek6v000bz0iwbbifdamq","category_id":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek750015z0iw8y7p8xnn"},{"post_id":"clb4fek6v000bz0iwbbifdamq","category_id":"clb4fek74000yz0iwhj62epp5","_id":"clb4fek760018z0iwfhn55cnj"},{"post_id":"clb4fek6x000ez0iwdsee9z80","category_id":"clb4fek73000pz0iwfg1k64ky","_id":"clb4fek76001az0iwa0hbglre"},{"post_id":"clb4fek6i0001z0iwb2lv12kv","category_id":"clb4fek6o0003z0iw546f6hwn","_id":"clb4fek76001cz0iw59r31rvk"},{"post_id":"clb4fek6i0001z0iwb2lv12kv","category_id":"clb4fek6z000jz0iwg39z2veu","_id":"clb4fek76001ez0iw5xoj1jwm"},{"post_id":"clb4fek6i0001z0iwb2lv12kv","category_id":"clb4fek750014z0iw5qu20s1v","_id":"clb4fek76001gz0iw81mf7msh"}],"PostTag":[{"post_id":"clb4fek6i0001z0iwb2lv12kv","tag_id":"clb4fek6q0004z0iw50tqebda","_id":"clb4fek6y000fz0iwc7ox7ncs"},{"post_id":"clb4fek6i0001z0iwb2lv12kv","tag_id":"clb4fek6u0009z0iw8mqv06pl","_id":"clb4fek6z000hz0iw803we65b"},{"post_id":"clb4fek6l0002z0iwe86z0b68","tag_id":"clb4fek6w000dz0iwdugu32ot","_id":"clb4fek72000mz0iwatkg5qg7"},{"post_id":"clb4fek6s0006z0iw11hdcegc","tag_id":"clb4fek6w000dz0iwdugu32ot","_id":"clb4fek74000uz0iwhc9y7hag"},{"post_id":"clb4fek6s0006z0iw11hdcegc","tag_id":"clb4fek72000oz0iwacn3cdcv","_id":"clb4fek74000vz0iwbd661bm8"},{"post_id":"clb4fek6t0007z0iwcu898an8","tag_id":"clb4fek73000sz0iw9bm99nz3","_id":"clb4fek74000zz0iw2a0keyit"},{"post_id":"clb4fek6u000az0iw8szb3o5l","tag_id":"clb4fek74000xz0iw4lgxh8re","_id":"clb4fek760017z0iwffib4t44"},{"post_id":"clb4fek6u000az0iw8szb3o5l","tag_id":"clb4fek740011z0iw7xk3btkc","_id":"clb4fek760019z0iw558p0crn"},{"post_id":"clb4fek6v000bz0iwbbifdamq","tag_id":"clb4fek750016z0iw31urb9ow","_id":"clb4fek76001fz0iw4zfsfdn1"},{"post_id":"clb4fek6v000bz0iwbbifdamq","tag_id":"clb4fek76001bz0iwbtzj9zng","_id":"clb4fek76001hz0iw59kbccw6"},{"post_id":"clb4fek6x000ez0iwdsee9z80","tag_id":"clb4fek76001dz0iw64g429yt","_id":"clb4fek77001lz0iwguj11p9n"},{"post_id":"clb4fek6x000ez0iwdsee9z80","tag_id":"clb4fek76001iz0iwevqj0t15","_id":"clb4fek77001mz0iw4vfufeg3"},{"post_id":"clb4fek6x000ez0iwdsee9z80","tag_id":"clb4fek76001jz0iw9lrt5dir","_id":"clb4fek77001oz0iwg34bfwh9"},{"post_id":"clb4fek6y000gz0iw1o0uh2v9","tag_id":"clb4fek76001kz0iw6pd7gyqo","_id":"clb4fek77001qz0iwcu6re6dc"},{"post_id":"clb4fek6y000gz0iw1o0uh2v9","tag_id":"clb4fek77001nz0iw5c4l67zf","_id":"clb4fek77001rz0iwcyv41jwf"},{"post_id":"clb4fek70000lz0iw9tba4mwz","tag_id":"clb4fek77001pz0iw3ulj8qkh","_id":"clb4fek77001vz0iw6ve60nty"},{"post_id":"clb4fek70000lz0iw9tba4mwz","tag_id":"clb4fek77001sz0iw2yhjhjng","_id":"clb4fek77001wz0iw4dufh2uu"},{"post_id":"clb4fek70000lz0iw9tba4mwz","tag_id":"clb4fek77001tz0iw97r58yme","_id":"clb4fek77001xz0iw5ysj4ren"},{"post_id":"clb4fek70000lz0iw9tba4mwz","tag_id":"clb4fek77001uz0iwa1fz6ty6","_id":"clb4fek77001yz0iwgf9i6wjw"}],"Tag":[{"name":"前端","_id":"clb4fek6q0004z0iw50tqebda"},{"name":"PrimeVue","_id":"clb4fek6u0009z0iw8mqv06pl"},{"name":"Docker","_id":"clb4fek6w000dz0iwdugu32ot"},{"name":"Bug","_id":"clb4fek72000oz0iwacn3cdcv"},{"name":"网易云","_id":"clb4fek73000sz0iw9bm99nz3"},{"name":"selenium","_id":"clb4fek74000xz0iw4lgxh8re"},{"name":"爬虫","_id":"clb4fek740011z0iw7xk3btkc"},{"name":"运维","_id":"clb4fek750016z0iw31urb9ow"},{"name":"ssh","_id":"clb4fek76001bz0iwbtzj9zng"},{"name":"收藏","_id":"clb4fek76001dz0iw64g429yt"},{"name":"网站","_id":"clb4fek76001iz0iwevqj0t15"},{"name":"工具","_id":"clb4fek76001jz0iw9lrt5dir"},{"name":"python","_id":"clb4fek76001kz0iw6pd7gyqo"},{"name":"pypi","_id":"clb4fek77001nz0iw5c4l67zf"},{"name":"代码片段","_id":"clb4fek77001pz0iw3ulj8qkh"},{"name":"Linux","_id":"clb4fek77001sz0iw2yhjhjng"},{"name":"Python","_id":"clb4fek77001tz0iw97r58yme"},{"name":"Git","_id":"clb4fek77001uz0iwa1fz6ty6"}]}}