init blog

This commit is contained in:
wxf
2025-06-13 16:30:38 +08:00
commit c685fa20eb
25 changed files with 33738 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+31
View File
@@ -0,0 +1,31 @@
{
"hash": "eaa9716f",
"configHash": "0787476f",
"lockfileHash": "3a2aa35b",
"browserHash": "cea78049",
"optimized": {
"vue": {
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "23d22a81",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "23e92d36",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "167f41fd",
"needsInterop": false
}
},
"chunks": {
"chunk-FA4MWVOB": {
"file": "chunk-FA4MWVOB.js"
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+343
View File
@@ -0,0 +1,343 @@
import {
BaseTransition,
BaseTransitionPropsValidators,
Comment,
DeprecationTypes,
EffectScope,
ErrorCodes,
ErrorTypeStrings,
Fragment,
KeepAlive,
ReactiveEffect,
Static,
Suspense,
Teleport,
Text,
TrackOpTypes,
Transition,
TransitionGroup,
TriggerOpTypes,
VueElement,
assertNumber,
callWithAsyncErrorHandling,
callWithErrorHandling,
camelize,
capitalize,
cloneVNode,
compatUtils,
compile,
computed,
createApp,
createBaseVNode,
createBlock,
createCommentVNode,
createElementBlock,
createHydrationRenderer,
createPropsRestProxy,
createRenderer,
createSSRApp,
createSlots,
createStaticVNode,
createTextVNode,
createVNode,
customRef,
defineAsyncComponent,
defineComponent,
defineCustomElement,
defineEmits,
defineExpose,
defineModel,
defineOptions,
defineProps,
defineSSRCustomElement,
defineSlots,
devtools,
effect,
effectScope,
getCurrentInstance,
getCurrentScope,
getCurrentWatcher,
getTransitionRawChildren,
guardReactiveProps,
h,
handleError,
hasInjectionContext,
hydrate,
hydrateOnIdle,
hydrateOnInteraction,
hydrateOnMediaQuery,
hydrateOnVisible,
initCustomFormatter,
initDirectivesForSSR,
inject,
isMemoSame,
isProxy,
isReactive,
isReadonly,
isRef,
isRuntimeOnly,
isShallow,
isVNode,
markRaw,
mergeDefaults,
mergeModels,
mergeProps,
nextTick,
normalizeClass,
normalizeProps,
normalizeStyle,
onActivated,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onScopeDispose,
onServerPrefetch,
onUnmounted,
onUpdated,
onWatcherCleanup,
openBlock,
popScopeId,
provide,
proxyRefs,
pushScopeId,
queuePostFlushCb,
reactive,
readonly,
ref,
registerRuntimeCompiler,
render,
renderList,
renderSlot,
resolveComponent,
resolveDirective,
resolveDynamicComponent,
resolveFilter,
resolveTransitionHooks,
setBlockTracking,
setDevtoolsHook,
setTransitionHooks,
shallowReactive,
shallowReadonly,
shallowRef,
ssrContextKey,
ssrUtils,
stop,
toDisplayString,
toHandlerKey,
toHandlers,
toRaw,
toRef,
toRefs,
toValue,
transformVNodeArgs,
triggerRef,
unref,
useAttrs,
useCssModule,
useCssVars,
useHost,
useId,
useModel,
useSSRContext,
useShadowRoot,
useSlots,
useTemplateRef,
useTransitionState,
vModelCheckbox,
vModelDynamic,
vModelRadio,
vModelSelect,
vModelText,
vShow,
version,
warn,
watch,
watchEffect,
watchPostEffect,
watchSyncEffect,
withAsyncContext,
withCtx,
withDefaults,
withDirectives,
withKeys,
withMemo,
withModifiers,
withScopeId
} from "./chunk-FA4MWVOB.js";
export {
BaseTransition,
BaseTransitionPropsValidators,
Comment,
DeprecationTypes,
EffectScope,
ErrorCodes,
ErrorTypeStrings,
Fragment,
KeepAlive,
ReactiveEffect,
Static,
Suspense,
Teleport,
Text,
TrackOpTypes,
Transition,
TransitionGroup,
TriggerOpTypes,
VueElement,
assertNumber,
callWithAsyncErrorHandling,
callWithErrorHandling,
camelize,
capitalize,
cloneVNode,
compatUtils,
compile,
computed,
createApp,
createBlock,
createCommentVNode,
createElementBlock,
createBaseVNode as createElementVNode,
createHydrationRenderer,
createPropsRestProxy,
createRenderer,
createSSRApp,
createSlots,
createStaticVNode,
createTextVNode,
createVNode,
customRef,
defineAsyncComponent,
defineComponent,
defineCustomElement,
defineEmits,
defineExpose,
defineModel,
defineOptions,
defineProps,
defineSSRCustomElement,
defineSlots,
devtools,
effect,
effectScope,
getCurrentInstance,
getCurrentScope,
getCurrentWatcher,
getTransitionRawChildren,
guardReactiveProps,
h,
handleError,
hasInjectionContext,
hydrate,
hydrateOnIdle,
hydrateOnInteraction,
hydrateOnMediaQuery,
hydrateOnVisible,
initCustomFormatter,
initDirectivesForSSR,
inject,
isMemoSame,
isProxy,
isReactive,
isReadonly,
isRef,
isRuntimeOnly,
isShallow,
isVNode,
markRaw,
mergeDefaults,
mergeModels,
mergeProps,
nextTick,
normalizeClass,
normalizeProps,
normalizeStyle,
onActivated,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onScopeDispose,
onServerPrefetch,
onUnmounted,
onUpdated,
onWatcherCleanup,
openBlock,
popScopeId,
provide,
proxyRefs,
pushScopeId,
queuePostFlushCb,
reactive,
readonly,
ref,
registerRuntimeCompiler,
render,
renderList,
renderSlot,
resolveComponent,
resolveDirective,
resolveDynamicComponent,
resolveFilter,
resolveTransitionHooks,
setBlockTracking,
setDevtoolsHook,
setTransitionHooks,
shallowReactive,
shallowReadonly,
shallowRef,
ssrContextKey,
ssrUtils,
stop,
toDisplayString,
toHandlerKey,
toHandlers,
toRaw,
toRef,
toRefs,
toValue,
transformVNodeArgs,
triggerRef,
unref,
useAttrs,
useCssModule,
useCssVars,
useHost,
useId,
useModel,
useSSRContext,
useShadowRoot,
useSlots,
useTemplateRef,
useTransitionState,
vModelCheckbox,
vModelDynamic,
vModelRadio,
vModelSelect,
vModelText,
vShow,
version,
warn,
watch,
watchEffect,
watchPostEffect,
watchSyncEffect,
withAsyncContext,
withCtx,
withDefaults,
withDirectives,
withKeys,
withMemo,
withModifiers,
withScopeId
};
//# sourceMappingURL=vue.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+35
View File
@@ -0,0 +1,35 @@
import { defineConfig } from 'vitepress'
export default defineConfig({
title: "fly's Blog",
description: '记录技术成长与生活点滴,分享有趣的世界。',
lang: 'zh-CN',
themeConfig: {
sidebar: {
'/notes/': [
{ text: 'HTML', link: '/notes/html' },
{ text: 'Vue', link: '/notes/vue' },
{ text: 'React', link: '/notes/react' },
{ text: 'JS', link: '/notes/js' },
{ text: 'CSS', link: '/notes/css' },
{ text: 'Webpack', link: '/notes/webpack' },
{ text: 'Git', link: '/notes/git' }
],
'/share/': [
{ text: '分享', link: '/share/share' }
]
},
socialLinks: [
{ icon: 'gitea', link: 'http://124.221.147.173:3000/' }
],
footer: {
message: '本项目采用 MIT 许可协议发布。',
copyright: '版权所有 © 2024-present 王鑫飞 (fly)'
}
},
markdown: {
lineNumbers: true
},
lastUpdated: true,
appearance: false // 禁用主题切换
})
+590
View File
@@ -0,0 +1,590 @@
:root {
--main-bg: #f6f8fa;
--sidebar-bg: #fff;
--sidebar-border: #e5e7eb;
--sidebar-active: #2563eb;
--sidebar-hover: #e8f0fe;
--sidebar-title: #6b7280;
--sidebar-text: #374151;
--content-bg: #fff;
--content-shadow: 0 4px 24px 0 rgba(30, 34, 54, 0.08);
--content-radius: 16px;
--main-font: 'Inter', 'Segoe UI', 'Roboto', 'Arial', sans-serif;
--main-link: #2563eb;
--main-link-hover: #1d4ed8;
--main-title: #1e293b;
--main-subtitle: #374151;
--main-border: #e5e7eb;
--main-muted: #6b7280;
}
body {
background: var(--main-bg);
min-height: 100vh;
font-family: var(--main-font);
color: var(--main-subtitle);
letter-spacing: 0.01em;
}
/* 顶部导航栏品牌化美化 */
.VPNavBar {
justify-content: center !important;
align-items: center !important;
min-height: 64px;
box-shadow: 0 2px 8px 0 rgba(30, 34, 54, 0.04);
border-bottom: 1px solid #e5e7eb;
}
.VPNavBar .title {
font-size: 1.5rem !important;
font-weight: 800 !important;
color: #1e293b !important;
margin: 0 auto !important;
letter-spacing: 0.01em;
display: flex;
align-items: center;
gap: 0.6rem;
}
.VPNavBar .VPNavBarMenu {
margin-left: auto !important;
}
.VPNavBar .VPNavBarMenuLink {
font-size: 1.1rem;
}
@media (max-width: 700px) {
.VPNavBar .title {
font-size: 1.1rem !important;
gap: 0.3rem;
}
.VPNavBar .VPNavBarMenuLink {
font-size: 1rem;
}
.VPNavBar {
min-height: 48px;
padding: 0 0.5rem;
}
}
/* 侧边栏 */
.VPSidebar {
background: var(--sidebar-bg) !important;
border-right: 1px solid var(--sidebar-border);
box-shadow: none;
border-radius: 0 0 0 0;
backdrop-filter: none;
}
/* 侧边栏菜单项 */
.VPSidebar .item {
color: var(--sidebar-text);
background: transparent !important;
border-radius: 10px;
margin: 0.3rem 0.8rem;
transition: all 0.18s cubic-bezier(.4,0,.2,1);
font-weight: 500;
box-shadow: none;
border: none;
}
.VPSidebar .item:hover {
background: var(--sidebar-hover) !important;
color: var(--sidebar-active) !important;
transform: translateX(4px);
}
.VPSidebar .item.active {
background: var(--sidebar-active) !important;
color: #fff !important;
font-weight: 700;
}
.VPSidebar .group .title {
color: var(--sidebar-title);
font-size: 0.92rem;
font-weight: 700;
letter-spacing: 0.08em;
margin: 1.2rem 0 0.5rem 1.2rem;
text-shadow: none;
}
/* 内容区卡片化 */
.VPContent {
background: var(--content-bg);
border-radius: var(--content-radius);
box-shadow: var(--content-shadow);
padding: 2.2rem 2.2rem 2rem 2.2rem;
margin: 2rem 2vw;
border: 1px solid var(--main-border);
backdrop-filter: none;
}
/* 标题 */
h1, h2 {
color: var(--main-title);
font-weight: 800;
letter-spacing: 0.01em;
}
h3, h4, h5, h6 {
color: var(--main-subtitle);
font-weight: 700;
}
/* 链接 */
a {
color: var(--main-link);
text-decoration: none;
transition: color 0.2s;
}
a:hover {
color: var(--main-link-hover);
}
/* 表格 */
table {
background: #fff;
border-radius: 10px;
box-shadow: 0 2px 8px 0 rgba(30, 34, 54, 0.04);
border: 1px solid var(--main-border);
overflow: hidden;
}
th, td {
padding: 0.8rem 1.2rem;
border: none;
}
th {
color: var(--main-title);
background: #f3f4f6;
}
td {
color: var(--main-subtitle);
}
/* 引用块 */
blockquote {
border-left: 4px solid var(--main-link);
background: #f3f4f6;
color: var(--main-muted);
border-radius: 0 10px 10px 0;
box-shadow: none;
}
/* 按钮 */
button {
background: #f4f6fa;
color: #2563eb;
border: none;
border-radius: 8px;
box-shadow: 0 2px 8px 0 rgba(30,34,54,0.06);
font-weight: 600;
font-size: 1.05em;
padding: 0.7rem 1.6rem;
cursor: pointer;
transition: background 0.18s, color 0.18s, box-shadow 0.18s;
}
button:hover, button:active {
background: #2563eb;
color: #fff;
box-shadow: 0 4px 16px rgba(37,99,235,0.10);
}
/* 滚动条 */
::-webkit-scrollbar {
width: 8px;
height: 0px; /* 隐藏水平滚动条 */
background: #f3f4f6;
}
::-webkit-scrollbar-thumb {
background: #b0b4ba;
border-radius: 8px;
transition: background 0.2s;
}
::-webkit-scrollbar-thumb:hover {
background: #888c94;
}
::-webkit-scrollbar-corner {
background: #f3f4f6;
}
/* 通用隐藏水平滚动条 */
body, html, .VPContent, .VPSidebar {
overflow-x: hidden !important;
}
/* 响应式适配 */
@media (max-width: 900px) {
.VPContent {
padding: 1rem 0.5rem;
margin: 1rem 0.5vw;
}
.VPSidebar {
border-radius: 0 !important;
}
}
/* 隐藏主题切换按钮 */
.VPNav .VPNavBar .content .content-body .VPNavBarMenuLink.theme {
display: none;
}
/* 隐藏主题切换面板 */
.VPSwitchAppearance {
display: none !important;
}
/* 防止锚点定位时出现白色补白 */
.VPDoc .content {
margin-top: 0 !important;
padding-top: 0 !important;
}
/* 已移除自定义代码块样式,恢复 VitePress 默认代码高亮 */
/* 首页隐藏侧边栏、页脚、目录等 */
body.home .VPSidebar,
body.home .VPDocFooter,
body.home .VPDocAside,
body.home .VPDocOutline,
body.home .VPContent .VPNav,
body.home .VPContent .VPDocFooter,
body.home .VPContent .VPDocOutline {
display: none !important;
}
body.home .VPContent {
max-width: 900px;
margin: 0 auto;
padding: 0;
box-shadow: none;
border: none;
background: transparent;
}
/* 首页整体居中美化 */
.blog-home-wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 70vh;
padding-top: 4vh;
}
.blog-home-title {
font-size: 2.8rem;
font-weight: 800;
color: #1e293b;
margin-bottom: 1.2rem;
letter-spacing: 0.01em;
}
.blog-home-desc {
font-size: 1.25rem;
color: #374151;
margin-bottom: 2.5rem;
}
.blog-home-cards {
display: flex;
gap: 2.2rem;
flex-wrap: wrap;
justify-content: center;
}
.blog-home-card {
display: flex;
flex-direction: column;
align-items: center;
min-width: 240px;
max-width: 320px;
background: #fff;
border-radius: 18px;
box-shadow: 0 4px 24px rgba(30,34,54,0.08);
padding: 2.2rem 1.5rem;
text-decoration: none;
transition: box-shadow .2s, transform .2s;
border: 1.5px solid #f3f4f6;
}
.blog-home-card .icon {
font-size: 2.5rem;
margin-bottom: 0.8rem;
}
.blog-home-card .title {
font-size: 1.4rem;
font-weight: 700;
margin-bottom: 0.5rem;
color: #2563eb;
}
.blog-home-card .desc {
font-size: 1rem;
color: #6b7280;
opacity: .92;
}
.blog-home-card.tech {
background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
color: #fff;
border: none;
}
.blog-home-card.tech .title {
color: #fff;
}
.blog-home-card.tech .desc {
color: #e0e6ff;
}
.blog-home-card.share {
border: 1.5px solid #2563eb;
}
.blog-home-card:hover {
transform: translateY(-8px) scale(1.03);
box-shadow: 0 8px 32px rgba(37,99,235,0.10);
}
@media (max-width: 700px) {
.blog-home-cards { flex-direction: column; gap: 1.2rem; }
.blog-home-wrapper { padding-top: 2vh; }
}
/* WordPress风格首页美化 */
.wp-home-wrapper {
max-width: 900px;
margin: 0 auto;
padding: 0 1.5rem 3rem 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
}
.wp-home-header {
display: flex;
align-items: center;
gap: 2rem;
margin-top: 4rem;
margin-bottom: 3rem;
}
.wp-home-avatar {
width: 90px;
height: 90px;
border-radius: 50%;
box-shadow: 0 2px 12px rgba(30,34,54,0.10);
border: 3px solid #fff;
background: #f3f4f6;
}
.wp-home-title {
font-size: 2.4rem;
font-weight: 800;
color: #1e293b;
margin-bottom: 0.5rem;
letter-spacing: 0.01em;
}
.wp-home-desc {
font-size: 1.15rem;
color: #374151;
margin-bottom: 0;
}
.wp-home-cards {
display: flex;
gap: 2.2rem;
flex-wrap: wrap;
justify-content: center;
width: 100%;
}
.wp-home-card {
display: flex;
flex-direction: column;
align-items: center;
min-width: 240px;
max-width: 340px;
background: #fff;
border-radius: 18px;
box-shadow: 0 4px 24px rgba(30,34,54,0.08);
padding: 2.2rem 1.5rem 2rem 1.5rem;
text-decoration: none;
transition: box-shadow .2s, transform .2s;
border: 1.5px solid #f3f4f6;
margin-bottom: 1.5rem;
}
.wp-home-card-icon {
font-size: 2.5rem;
margin-bottom: 0.8rem;
}
.wp-home-card-title {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 0.5rem;
color: #2563eb;
}
.wp-home-card-desc {
font-size: 1rem;
color: #6b7280;
opacity: .92;
margin-bottom: 1.2rem;
text-align: center;
}
.wp-home-card-btn {
display: inline-block;
background: #2563eb;
color: #fff;
border-radius: 8px;
padding: 0.6rem 1.4rem;
font-weight: 600;
font-size: 1.05em;
box-shadow: 0 2px 8px 0 rgba(30, 34, 54, 0.08);
border: none;
text-decoration: none;
transition: background 0.18s, color 0.18s, box-shadow 0.18s;
}
.wp-home-card-btn:hover {
background: #1d4ed8;
color: #fff;
box-shadow: 0 4px 16px rgba(37,99,235,0.10);
}
.wp-home-card-btn-outline {
background: #fff;
color: #2563eb;
border: 1.5px solid #2563eb;
}
.wp-home-card-btn-outline:hover {
background: #2563eb;
color: #fff;
}
@media (max-width: 700px) {
.wp-home-header {
flex-direction: column;
gap: 1.2rem;
margin-top: 1.2rem;
margin-bottom: 1.2rem;
align-items: center;
}
.wp-home-avatar {
width: 64px;
height: 64px;
}
.wp-home-title {
font-size: 1.4rem;
text-align: center;
}
.wp-home-desc {
font-size: 1rem;
text-align: center;
}
.wp-home-cards {
flex-direction: column;
gap: 1.2rem;
width: 100%;
align-items: center;
}
.wp-home-card {
min-width: unset;
max-width: 98vw;
width: 100%;
padding: 1.2rem 0.5rem 1.2rem 0.5rem;
margin-bottom: 0.8rem;
}
.wp-home-card-title {
font-size: 1.1rem;
}
.wp-home-card-desc {
font-size: 0.95rem;
}
.wp-home-card-btn, .wp-home-card-btn-outline {
font-size: 1rem;
padding: 0.5rem 1rem;
}
.wp-home-wrapper {
padding: 0 0.2rem 1.2rem 0.2rem;
min-height: unset;
}
}
body.home {
background: url('https://img1.doubanio.com/view/photo/l/public/p2614988096.webp') center center/cover no-repeat fixed !important;
position: relative;
}
body.home::before {
content: '';
position: fixed;
left: 0; top: 0; right: 0; bottom: 0;
background: rgba(255,255,255,0.72);
z-index: 0;
pointer-events: none;
}
.wp-home-wrapper, .blog-home-wrapper {
position: relative;
z-index: 1;
}
body.home .VPSwitchBackToTop,
body.home .VPBackToTop {
display: none !important;
}
/* 全局美化 VitePress 移动端菜单按钮 */
/* 主菜单、三点、锚点、侧边栏等所有按钮统一风格 */
.VPNavBarMenu button,
.VPNavBarMenu .VPNavBarMenuGroupBtn,
.VPNavBarMenu .VPNavBarMenuLink {
background: #fff !important;
color: #1e293b !important;
border-radius: 10px !important;
border: 1.5px solid #e5e7eb !important;
box-shadow: 0 2px 8px 0 rgba(30,34,54,0.08) !important;
min-width: 44px;
min-height: 44px;
position: relative;
overflow: visible;
}
/* 强制显示按钮内的svg图标 */
.VPNavBarMenu button svg,
.VPNavBarMenu .VPNavBarMenuGroupBtn svg,
.VPNavBarMenu .VPNavBarMenuLink svg {
display: inline-block !important;
opacity: 1 !important;
color: #1e293b !important;
fill: #1e293b !important;
width: 1.6em !important;
height: 1.6em !important;
vertical-align: middle;
}
/* 如果按钮内容为空,给个默认icon(仅兜底,正常不会触发) */
.VPNavBarMenu button:empty::after,
.VPNavBarMenu .VPNavBarMenuGroupBtn:empty::after {
content: '\\22EE'; /* 竖向三点 ⋮ */
color: #1e293b;
font-size: 2em;
display: block;
text-align: center;
line-height: 44px;
}
/* 只在小屏显示汉堡菜单按钮,大屏隐藏 */
.VPNavBarHamburger {
display: none !important;
}
@media (max-width: 700px) {
.VPNavBarHamburger {
display: flex !important;
}
}
/* 只美化移动端汉堡菜单按钮 */
button.VPNavBarHamburger.hamburger {
background: #fff !important;
border-radius: 10px !important;
border: 1.5px solid #e5e7eb !important;
box-shadow: 0 2px 8px 0 rgba(30,34,54,0.08) !important;
width: 44px;
height: 44px;
padding: 0 !important;
display: flex;
align-items: center;
justify-content: center;
}
button.VPNavBarHamburger.hamburger .container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 24px;
width: 24px;
}
button.VPNavBarHamburger.hamburger .top,
button.VPNavBarHamburger.hamburger .middle,
button.VPNavBarHamburger.hamburger .bottom {
display: block;
width: 22px;
height: 3px;
background: #1e293b !important; /* 深色主色 */
border-radius: 2px;
margin: 2.5px 0;
transition: background 0.18s;
}
+10
View File
@@ -0,0 +1,10 @@
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default {
...DefaultTheme,
enhanceApp({ app }) {
// 在这里可以注册全局组件或添加其他配置
}
}
+35
View File
@@ -0,0 +1,35 @@
---
title: 博客首页
layout: home
---
<div class="wp-home-wrapper">
<div class="wp-home-header">
<img src="https://q.qlogo.cn/g?b=qq&nk=3505891631&s=100" alt="fly头像" class="wp-home-avatar" />
<div>
<h1 class="wp-home-title">fly's Blog</h1>
<p class="wp-home-desc">前端开发者 | 记录技术成长与生活点滴,分享有趣的世界。</p>
</div>
</div>
<div class="wp-home-cards">
<div class="wp-home-card">
<div class="wp-home-card-icon">💻</div>
<div class="wp-home-card-title">技术笔记</div>
<div class="wp-home-card-desc">记录我的前端成长路。</div>
<a href="/notes/html" class="wp-home-card-btn">进入技术笔记</a>
</div>
<div class="wp-home-card">
<div class="wp-home-card-icon">🌈</div>
<div class="wp-home-card-title">日常分享</div>
<div class="wp-home-card-desc">音乐、书籍、美食,和生活。</div>
<a href="/share/share" class="wp-home-card-btn wp-home-card-btn-outline">进入日常分享</a>
</div>
</div>
</div>
<style>
@media (max-width: 700px) {
.vp-doc div[style*='display: flex'] { flex-direction: column !important; gap: 1.2rem !important; }
}
.vp-doc a:hover > div { transform: translateY(-6px) scale(1.03); box-shadow:0 8px 32px rgba(37,99,235,0.10); }
</style>
+49
View File
@@ -0,0 +1,49 @@
# 1. CSS
## 1.1 基础选择器
### 1.1.1 元素选择器
```css
p {
color: blue;
}
```
### 1.1.2 类选择器
```css
.container {
width: 100%;
}
```
### 1.1.3 ID 选择器
```css
#header {
background-color: gray;
}
```
## 1.2 盒模型
```css
.box {
width: 200px;
height: 200px;
padding: 20px;
border: 1px solid black;
margin: 10px;
}
```
## 1.3 布局
### 1.3.1 Flex 布局
```css
.flex-container {
display: flex;
justify-content: space-between;
align-items: center;
}
```
### 1.3.2 Grid 布局
```css
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
+197
View File
@@ -0,0 +1,197 @@
## 1. Git基础
### 1.1 版本管理
#### 1.1.1 什么是版本管理
版本管理是一种记录文件变化的方式,以便将来查阅特定版本的文件内容。
#### 1.1.2 人为维护文档版本的问题
1. 文档数量多且命名不清晰导致文档版本混乱
2. 每次编辑文档需要复制,不方便
3. 多人同时编辑同一个文档,容易产生覆盖
### 1.2 Git 是什么
Git是一个版本管理控制系统(缩写VCS),它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点,将更新记录恢复回来。
### 1.3 Git 安装
[下载地址](https://git-scm.com/downloads)
在安装的过程中,所有选项使用默认值即可。
### 1.4 Git 基本工作流程
| git仓库 | 暂存区 | 工作目录 |
| ---------------- | ------------------ | ------------------- |
| 用于存放提交记录 | 临时存放被修改文件 | 被Git管理的项目目录 |
### 1.5 Git 的使用
#### 1.5.1 Git 使用前配置
在使用 git 前,需要告诉 git 你是谁,在向 git 仓库中提交时需要用到。
1. 配置提交人姓名:`git config --global user.name 提交人姓名`
2. 配置提交人姓名:`git config --global user.email 提交人邮箱`
3. 查看git配置信息:`git config --list`
**注意**
1. 如果要对配置信息进行修改,重复上述命令即可。
2. 配置只需要执行一次。
#### 1.5.2 提交步骤
1. `git init` 初始化git仓库
2. `git status` 查看文件状态
3. `git add 文件列表` 追踪文件
4. `git commit -m 提交信息` 向仓库中提交代码
5. `git log` 查看提交记录
#### 1.5.3 撤销
- 用暂存区中的文件覆盖工作目录中的文件: `git checkout 文件`
- 将文件从暂存区中删除: `git rm --cached 文件`
- 将 git 仓库中指定的更新记录恢复出来,并且覆盖暂存区和工作目录:`git rest --hard commitID`
## 2. Git进阶
### 2.1 分支
为了便于理解,大家暂时可以认为分支就是当前工作目录中代码的一份副本。
使用分支,可以让我们从开发主线上分离出来,以免影响开发主线。
#### 2.1.1 分支细分
1. 主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
2. 、开发分支(develop):作为开发的分支,基于 master 分支创建。
3. 功能分支(feature):作为开发具体功能的分支,基于开发分支创建
**功能分支 -> 开发分支 -> 主分支**
#### 2.1.2 分支命令
- `git branch` 查看分支
- `git branch 分支名称` 创建分支
- `git checkout 分支名称` 切换分支
- `git checkout -b master origin/分支名称` 创建并切换分支并拉取代码
- `git merge 来源分支` 合并分支
- `git branch -d 分支名称` 删除分支(分支被合并后才允许删除)(-D 强制删除)
### 2.2 暂时保存更改
在git中,可以暂时提取分支上所有的改动并存储,让开发人员得到一个干净的工作副本,临时转向其他工作。
使用场景:分支临时切换
- 存储临时改动:`git stash`
- 恢复改动:`git stash pop`
## 3. Github
在版本控制系统中,大约90%的操作都是在本地仓库中进行的:暂存,提交,查看状态或者历史记录等等。除此之外,如果仅仅只有你一个人在这个项目里工作,你永远没有机会需要设置一个远程仓库。
只有当你需要和你的开发团队共享数据时,设置一个远程仓库才有意义。你可以把它想象成一个 “文件管理服务器”,利用这个服务器可以与开发团队的其他成员进行数据交换。
### 3.1 注册
1. 访问[github](https://github.com/)首页,点击 Sign up 连接。(注册)
2. 填写用户名、邮箱地址、GitHub登陆密码
3. 选择计划
4. 填写 GitHub 问题
5. 验证邮箱
6. GitHub 个人中心
### 3.2 多人协作开发流程
- A在自己的计算机中创建本地仓库
- A在github中创建远程仓库
- A将本地仓库推送到远程仓库
- B克隆远程仓库到本地进行开发
- B将本地仓库中开发的内容推送到远程仓库
- A将远程仓库中的最新内容拉去到本地
### 3.3 创建仓库
1. 填写仓库基本信息
2. 将本地仓库推送到远程仓库
1. git push 远程仓库地址 分支名称
2. git push 远程仓库地址别名 分支名称
3. git push -u 远程仓库地址别名 分支名称
-u 记住推送地址及分支,下次推送只需要输入git push即可
4. git remote add 远程仓库地址别名 远程仓库地址
### 3.4 拉取操作
#### 3.4.1 克隆仓库
克隆远端数据仓库到本地:`git clone 仓库地址`
#### 3.4.2 拉取远程仓库中最新的版本
拉取远程仓库中最新的版本:`git pull 远程仓库地址 分支名称`
### 3.5 解决冲突
在多人同时开发一个项目时,如果两个人修改了同一个文件的同一个地方,就会发生冲突。冲突需要人为解决。
### 3.6 跨团队协作
1. 程序员 C fork仓库
2. 程序员 C 将仓库克隆在本地进行修改
3. 程序员 C 将仓库推送到远程
4. 程序员 C 发起pull reqest
5. 原仓库作者审核
6. 原仓库作者合并代码
### 3.7 ssh免登陆
https协议仓库地址:https://github.com/itcast-frontEnd/git-demo.git
生成秘钥:`ssh-keygen`
秘钥存储目录:C:\Users\用户\.ssh
公钥名称:id_rsa.pub
私钥名称:id_rsa
### 3.8 GIT忽略清单
将不需要被git管理的文件名字添加到此文件中,在执行git命令的时候,git就会忽略这些文件。
git忽略清单文件名称:**.gitignore**
将工作目录中的文件全部添加到暂存区:`git add .`
+49
View File
@@ -0,0 +1,49 @@
# 1. HTML
## 1.1 基本结构
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>示例页面</title>
</head>
<body>
<h1>欢迎来到我的页面</h1>
<p>这是一个简单的 HTML 示例。</p>
</body>
</html>
```
## 1.2 常用标签
### 1.2.1 标题标签
```html
<h1>一级标题</h1>
<h2>二级标题</h2>
<h3>三级标题</h3>
```
### 1.2.2 段落标签
```html
<p>这是一个段落。</p>
```
### 1.2.3 链接标签
```html
<a href="https://www.example.com">访问示例网站</a>
```
### 1.2.4 图片标签
```html
<img src="image.jpg" alt="示例图片">
```
## 1.3 表单元素
```html
<form action="submit.php" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username">
<br>
<label for="password">密码:</label>
<input type="password" id="password" name="password">
<br>
<input type="submit" value="提交">
</form>
+1107
View File
File diff suppressed because it is too large Load Diff
+359
View File
@@ -0,0 +1,359 @@
# 1. React
## 1.1 脚手架文件结构
```
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.svg
│ ├── components: 存放组件
│ │ └── HelloWorld.jsx
│ ├── App.jsx: 汇总所有组件
│ └── index.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
└── package-lock.json:包版本控制文件
```
## 1.2 React 核心概念
### 1.2.1 JSX
#### 1. 定义
JSX 是 JavaScript XML 的缩写,它允许在 JavaScript 代码中编写类似 HTML 的结构,最终会被 Babel 等工具编译为 React 元素。
#### 2. 基本语法
JSX 看起来像 HTML,但实际上是 JavaScript 语法扩展,必须包含在一个根元素中。示例:
```jsx
const element = (
<div>
<h1>Hello, world!</h1>
<p>Welcome to React.</p>
</div>
);
```
#### 3. 表达式嵌入
在 JSX 中可以使用花括号 `{}` 嵌入 JavaScript 表达式。示例:
```jsx
const name = 'Alice';
const element = <h1>Hello, {name}</h1>;
```
#### 4. 样式处理
在 JSX 中使用 `style` 属性设置内联样式,属性值为一个 JavaScript 对象,键采用驼峰命名法。示例:
```jsx
const element = <div style={{ color: 'blue', fontSize: '20px' }}>Styled text</div>;
```
#### 5. 类名设置
由于 `class` 是 JavaScript 保留字,在 JSX 中使用 `className` 来设置 HTML 元素的类名。示例:
```jsx
const element = <div className="container">Container element</div>;
```
### 1.2.2 组件
#### 1. 函数组件
函数组件是一个返回 JSX 的 JavaScript 函数,接收 `props` 作为参数。示例:
```jsx
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
```
#### 2. 类组件
类组件继承自 `React.Component`,必须实现 `render` 方法返回 JSX。示例:
```jsx
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
```
### 1.2.6 事件处理
在 React 中,事件处理与 HTML 类似,但采用驼峰命名法,并且通过传递函数来处理事件。示例:
```jsx
function Button() {
const handleClick = () => {
alert('Button clicked!');
};
return (
<button onClick={handleClick}>Click me</button>
);
}
```
### 1.2.7 条件渲染
在 React 中可以使用 JavaScript 逻辑进行条件渲染。示例:
```jsx
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please sign up.</h1>;
}
```
还可以使用三元运算符和逻辑与运算符进行条件渲染:
```jsx
// 三元运算符
const element = isLoggedIn ? <LogoutButton /> : <LoginButton />;
// 逻辑与运算符
const unreadMessages = ['React', 'Re: React', 'Re:Re: React'];
const element = (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 && (
<h2>You have {unreadMessages.length} unread messages.</h2>
)}
</div>
);
```
### 1.2.3 状态(State
1. 功能:用于管理组件内部的数据。
2. 示例:
```jsx
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
```
### 1.2.4 生命周期方法
1. `componentDidMount()`:组件挂载后执行,常用于数据请求。
2. `componentDidUpdate()`:组件更新后执行。
3. `componentWillUnmount()`:组件卸载前执行,常用于清理工作。
### 1.2.5 状态提升
当多个组件需要共享状态时,通常会将状态提升到最近的共同父组件中。通过父组件传递 `props` 和回调函数,实现子组件与父组件之间的状态同步。
```jsx
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
```
## 1.3 React Hooks
### 1.3.1 useState
`useState` 是一个基础的 Hook,用于在函数组件中添加状态。示例如下:
```jsx
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
```
### 1.3.2 useEffect
`useEffect` 可以让你在函数组件中执行副作用操作,比如数据获取、订阅或手动修改 DOM。示例如下:
```jsx
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
```
## 1.4 React 路由
### 1.4.1 基本使用
1. 安装:`npm install react-router-dom`
2. 示例:
```jsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<Router>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
);
}
function Home() {
return <h1>Home Page</h1>;
}
function About() {
return <h1>About Page</h1>;
}
```
## 1.5 React 上下文(Context
### 1.5.1 功能
用于在组件树中共享数据,避免逐层传递 props。
### 1.5.2 示例
```jsx
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext();
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>I am styled by theme context!</button>;
}
```
## 1.6 React 优化
### 1.6.1 `React.memo`
用于优化函数组件,避免不必要的渲染。
```jsx
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
});
```
### 1.6.2 `useCallback` 和 `useMemo`
1. `useCallback`:缓存函数,避免每次渲染都重新创建。
- **原理**`useCallback` 接收一个回调函数和依赖项数组作为参数,返回一个 memoized 版本的回调函数,该回调函数仅在某个依赖项改变时才会更新。这有助于在传递回调函数给子组件时,避免不必要的重新渲染。
- **使用场景**:当你将回调函数作为 props 传递给子组件,并且子组件使用 `React.memo` 进行优化时,使用 `useCallback` 可以确保子组件不会因为回调函数的变化而不必要地重新渲染。
- **示例代码**
```jsx
import React, { useState, useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const [value, setValue] = useState('');
// 使用 useCallback 缓存函数
const handleClick = useCallback(() => {
console.log(`Count is: ${count}`);
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<Child handleClick={handleClick} />
</div>
);
}
const Child = React.memo(function Child({ handleClick }) {
return (
<button onClick={handleClick}>Click me</button>
);
});
```
2. `useMemo`:缓存计算结果,避免重复计算。
- **原理**`useMemo` 接收一个计算函数和依赖项数组作为参数,返回一个 memoized 的计算结果。仅当某个依赖项改变时,才会重新执行计算函数。
- **使用场景**:当你有一个计算开销较大的函数,并且该函数的输入依赖于某些状态或 props 时,使用 `useMemo` 可以避免在每次渲染时都重新计算结果。
- **示例代码**
```jsx
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [value, setValue] = useState('');
// 使用 useMemo 缓存计算结果
const expensiveValue = useMemo(() => {
console.log('Calculating expensive value...');
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<p>Expensive Value: {expensiveValue}</p>
</div>
);
}
```
+1456
View File
File diff suppressed because it is too large Load Diff
+119
View File
@@ -0,0 +1,119 @@
# 1. Webpack
## 1.1 基础概念
### 1.1.1 入口(Entry
入口起点指示 Webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。示例配置如下:
```javascript
// webpack.config.js
module.exports = {
entry: './src/index.js'
};
```
### 1.1.2 输出(Output
输出配置告诉 Webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。示例配置如下:
```javascript
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
```
## 1.2 加载器(Loaders
### 1.2.1 Babel Loader
用于将 ES6+ 代码转换为浏览器可兼容的 JavaScript 代码。安装和配置示例如下:
```bash
npm install --save-dev babel-loader @babel/core @babel/preset-env
```
```javascript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
};
```
### 1.2.2 CSS Loader 和 Style Loader
用于处理 CSS 文件。安装和配置示例如下:
```bash
npm install --save-dev css-loader style-loader
```
```javascript
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
```
## 1.3 插件(Plugins
### 1.3.1 HtmlWebpackPlugin
用于生成 HTML 文件,并自动注入打包后的 JavaScript 文件。安装和配置示例如下:
```bash
npm install --save-dev html-webpack-plugin
```
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
```
### 1.3.2 CleanWebpackPlugin
用于在每次构建前清理 `dist` 目录。安装和配置示例如下:
```bash
npm install --save-dev clean-webpack-plugin
```
```javascript
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin()
]
};
```
## 1.4 开发服务器(Dev Server
Webpack Dev Server 提供了一个简单的 Web 服务器,并且能够实时重新加载(Live Reloading)。安装和配置示例如下:
```bash
npm install --save-dev webpack-dev-server
```
```javascript
module.exports = {
devServer: {
contentBase: './dist',
open: true
}
};
```
运行开发服务器的命令:
```bash
npx webpack-dev-server --open
```
+16
View File
@@ -0,0 +1,16 @@
---
title: 日常分享
---
# 🌈 日常分享
这里会不定期记录我的音乐、书籍、美食、生活随笔等内容。
> 你可以在这里分享你的生活点滴,发现生活的美好。
- 🎵 音乐推荐
- 📚 书籍笔记
- 🍜 美食探店
- ✍️ 生活随笔
(你可以随时丰富和美化这个页面内容)
+2420
View File
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
{
"name": "vitepress-project",
"private": true,
"type": "module",
"scripts": {
"dev": "vitepress dev docs",
"build": "vitepress build docs",
"serve": "vitepress serve docs"
},
"devDependencies": {
"vue": "^3.2.47",
"vitepress": "^0.22.4"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search"
]
}
}
}