├── .gitignore ├── .vuepress ├── components │ └── ZanShang.vue ├── config.js ├── plugins │ ├── page-publish-date.js │ └── rss.js ├── public │ ├── 404.png │ ├── alipay.png │ ├── favicon.png │ ├── logo.png │ ├── search.svg │ └── wechatpay.png ├── styles │ └── palette.styl └── theme │ ├── components │ ├── AlgoliaSearchBox.vue │ ├── Category.vue │ ├── Comment.vue │ ├── Copyright.vue │ ├── DropdownLink.vue │ ├── DropdownTransition.vue │ ├── Footerbar.vue │ ├── Home.vue │ ├── NavLink.vue │ ├── NavLinks.vue │ ├── Navbar.vue │ ├── Page.vue │ ├── PostHeader.vue │ ├── PostItem.vue │ ├── SearchBox.vue │ ├── SidebarButton.vue │ └── Slogan.vue │ ├── enhance │ ├── filter.js │ ├── mixin.js │ ├── optionHandle.js │ └── routes.js │ ├── enhanceApp.js │ ├── global-components │ └── Badge.vue │ ├── index.js │ ├── layouts │ ├── 404.vue │ ├── CategoryLayout.vue │ └── Layout.vue │ ├── noopModule.js │ ├── styles │ ├── arrow.styl │ ├── code.styl │ ├── config.styl │ ├── custom-blocks.styl │ ├── index.styl │ ├── mobile.styl │ └── toc.styl │ └── util │ └── index.js ├── README.md ├── article ├── JS进制转换.md ├── about │ └── 关于我.md ├── hello.md ├── mysql设置密码.md ├── product │ └── 毕方铺网站简介.md ├── 为什么做个电子书网站.md ├── 关于我.md ├── 动物森友会.md └── 基于Vuepres搭建个人博客.md ├── images └── lizhi.png ├── package-lock.json ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | node_modules 4 | _book 5 | .vuepress/dist/* 6 | .vuepress/dist 7 | deploy.sh -------------------------------------------------------------------------------- /.vuepress/components/ZanShang.vue: -------------------------------------------------------------------------------- 1 | 11 | 26 | 79 | -------------------------------------------------------------------------------- /.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | base: '/', 3 | title: '毕方铺 - 博客', 4 | port: 8001, 5 | description: '我在技术、思想、产品、设计上的个人成长', 6 | head: [ 7 | ['meta', { name: 'keywords', content: '全栈开发,前端开发,后端开发,技术,产品,赚钱,读书,电影,音乐'}], 8 | ['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0'}], 9 | ['link', { rel: 'icon', href: '/favicon.png'}], 10 | ['script', { src: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.0/dist/av-min.js'}], 11 | ['script', { src: '//unpkg.com/valine/dist/Valine.min.js'}] 12 | ], 13 | plugins: [ 14 | require('./plugins/page-publish-date.js'), 15 | '@vuepress/pagination', 16 | [ 17 | '@vuepress/google-analytics', 18 | { 19 | 'ga': 'UA-139665684-1' 20 | } 21 | ], 22 | require('./plugins/rss.js'), 23 | ], 24 | markdown: { 25 | config: md => { 26 | md.set({ breaks: true }) 27 | }, 28 | anchor: { 29 | permalinkSymbol: '¶' 30 | }, 31 | }, 32 | themeConfig: { 33 | logo: '/logo.png', 34 | search: true, 35 | searchMaxSuggestions: 6, 36 | displayAllHeaders: true, 37 | lastUpdated: '上次修改时间', 38 | editLinks: true, 39 | editLinkText: 'Github修改此页面', 40 | repo: 'ChangMM/blog', 41 | nav: [ 42 | { text: '网盘搜索', link: 'https://www.iizhi.cn' }, 43 | // { text: '电影搜索', link: 'https://www.iizhi.cn/movie' }, 44 | // { text: '我的店铺', link: 'https://shop117651010.taobao.com/' } 45 | ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.vuepress/plugins/page-publish-date.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | module.exports = (options = {}, context) => ({ 4 | extendPageData ($page) { 5 | if (!$page.frontmatter.date) { 6 | $page.publishDate = getFilePublishDate($page._filePath) 7 | } else { 8 | $page.publishDate = $page.frontmatter.date 9 | } 10 | 11 | $page.lastUpdated = getFileLastUpdateDate() 12 | } 13 | }) 14 | 15 | function getFilePublishDate (filePath) { 16 | let publishDate 17 | try { 18 | publishDate = fs.statSync(filePath).birthtime 19 | } catch (e) { /* do not handle for now */ } 20 | return publishDate 21 | } 22 | 23 | function getFileLastUpdateDate (filePath) { 24 | let updateDate = new Date() 25 | try { 26 | updateDate = fs.statSync(filePath).mtime 27 | } catch (e) { /* do not handle for now */ } 28 | return updateDate 29 | } 30 | -------------------------------------------------------------------------------- /.vuepress/plugins/rss.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const RSS = require('rss') 3 | const chalk = require('chalk') 4 | 5 | module.exports = (pluginOptions, ctx) => { 6 | return { 7 | name: 'rss', 8 | 9 | generated () { 10 | const fs = require('fs-extra') 11 | const { pages, sourceDir } = ctx 12 | const siteData = require(path.resolve(sourceDir, '.vuepress/config.js')) 13 | 14 | const feed = new RSS({ 15 | title: siteData.title, 16 | description: siteData.description, 17 | feed_url: `https://blog.iizhi.cn/rss.xml`, 18 | site_url: `https://blog.iizhi.cn`, 19 | copyright: `明明三省`, 20 | language: 'en', 21 | }) 22 | 23 | pages 24 | .filter(page => { 25 | if (page.frontmatter.title === undefined) { 26 | return false 27 | } 28 | return page.path.indexOf('/article/') > -1 29 | }) 30 | .map(page => ({...page, date: new Date(page.frontmatter.date || '')})) 31 | .sort((a, b) => new Date(b.publishDate).getTime() - new Date(a.publishDate).getTime()) 32 | .map(page => ({ 33 | title: page.frontmatter.title, 34 | description: page.excerpt, 35 | url: `https://blog.iizhi.cn${page.path}`, 36 | date: page.publishDate, 37 | })) 38 | .slice(0, 20) 39 | .forEach(page => feed.item(page)) 40 | 41 | fs.writeFile( 42 | path.resolve(ctx.outDir, 'rss.xml'), 43 | feed.xml() 44 | ); 45 | console.log(chalk.green.bold('RSS has been generated!')) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.vuepress/public/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangMM/blog/cb06f7b1b42f36c42c3249627db943320d990e96/.vuepress/public/404.png -------------------------------------------------------------------------------- /.vuepress/public/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangMM/blog/cb06f7b1b42f36c42c3249627db943320d990e96/.vuepress/public/alipay.png -------------------------------------------------------------------------------- /.vuepress/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangMM/blog/cb06f7b1b42f36c42c3249627db943320d990e96/.vuepress/public/favicon.png -------------------------------------------------------------------------------- /.vuepress/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangMM/blog/cb06f7b1b42f36c42c3249627db943320d990e96/.vuepress/public/logo.png -------------------------------------------------------------------------------- /.vuepress/public/search.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.vuepress/public/wechatpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangMM/blog/cb06f7b1b42f36c42c3249627db943320d990e96/.vuepress/public/wechatpay.png -------------------------------------------------------------------------------- /.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | // colors 2 | $accentColor = #3354AA 3 | $textColor = #333 4 | $borderColor = #eee 5 | $codeBgColor = #282c34 6 | $arrowBgColor = #ccc 7 | $bgColor = #f5f5f5 8 | -------------------------------------------------------------------------------- /.vuepress/theme/components/AlgoliaSearchBox.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 61 | 62 | 156 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Category.vue: -------------------------------------------------------------------------------- 1 | 17 | 24 | 42 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Comment.vue: -------------------------------------------------------------------------------- 1 | 6 | 39 | 101 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Copyright.vue: -------------------------------------------------------------------------------- 1 | 10 | 68 | 80 | -------------------------------------------------------------------------------- /.vuepress/theme/components/DropdownLink.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 78 | 79 | 180 | -------------------------------------------------------------------------------- /.vuepress/theme/components/DropdownTransition.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 28 | 29 | 34 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Footerbar.vue: -------------------------------------------------------------------------------- 1 | 13 | 34 | 43 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Home.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /.vuepress/theme/components/NavLink.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 34 | -------------------------------------------------------------------------------- /.vuepress/theme/components/NavLinks.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 64 | 65 | 92 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | 30 | 80 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Page.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 150 | 151 | 238 | -------------------------------------------------------------------------------- /.vuepress/theme/components/PostHeader.vue: -------------------------------------------------------------------------------- 1 | 50 | 55 | 89 | -------------------------------------------------------------------------------- /.vuepress/theme/components/PostItem.vue: -------------------------------------------------------------------------------- 1 | 9 | 16 | 26 | -------------------------------------------------------------------------------- /.vuepress/theme/components/SearchBox.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 154 | 155 | 206 | -------------------------------------------------------------------------------- /.vuepress/theme/components/SidebarButton.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | -------------------------------------------------------------------------------- /.vuepress/theme/components/Slogan.vue: -------------------------------------------------------------------------------- 1 | 10 | 35 | 58 | -------------------------------------------------------------------------------- /.vuepress/theme/enhance/filter.js: -------------------------------------------------------------------------------- 1 | const install = (Vue) => { 2 | Vue.filter('toLocaleString', (date, locales) => { 3 | return new Date(date).toLocaleString(locales || 'en-US') 4 | }) 5 | 6 | Vue.filter('formatLocaleString', (value) => { 7 | return value.split(',')[0] 8 | }) 9 | } 10 | 11 | export default { install } 12 | -------------------------------------------------------------------------------- /.vuepress/theme/enhance/mixin.js: -------------------------------------------------------------------------------- 1 | import { isArray } from '../util' 2 | 3 | const install = (Vue, { pages }) => { 4 | let tagsMap = {} 5 | let categorysMap = {} 6 | let top = [] 7 | const posts = pages.filter(item => { 8 | if (item.frontmatter.title === undefined) { 9 | return false 10 | } 11 | return item.path.indexOf('/article/') > -1 12 | }).sort((item1, item2) => { 13 | return new Date(item2.publishDate).getTime() - new Date(item1.publishDate).getTime() 14 | }).map((item, index)=> { 15 | if (item.frontmatter.categorys instanceof String) { 16 | item.frontmatter.categorys = [item.frontmatter.categorys] 17 | } 18 | if (item.frontmatter.tags instanceof String) { 19 | item.frontmatter.tags = [item.frontmatter.tags] 20 | } 21 | item.index = index 22 | return item 23 | }) 24 | 25 | 26 | posts.forEach(item => { 27 | if (item.frontmatter.top !== undefined) { 28 | top.push(item) 29 | } 30 | 31 | let categorys = item.frontmatter.categorys 32 | if (!categorys) { 33 | categorys = [] 34 | } 35 | categorys.forEach(cate => { 36 | if (!categorysMap[cate]) { 37 | categorysMap[cate] = [item] 38 | } else { 39 | categorysMap[cate].push(item) 40 | } 41 | }) 42 | 43 | let tags = item.frontmatter.tags 44 | if (tags) { 45 | if (!isArray(tags)) { 46 | tags = [tags] 47 | } 48 | } else { 49 | tags = [] 50 | } 51 | tags.forEach(tag => { 52 | if (!tagsMap[tag]) { 53 | tagsMap[tag] = [item] 54 | } else { 55 | tagsMap[tag].push(item) 56 | } 57 | }) 58 | }) 59 | 60 | Vue.mixin({ 61 | computed: { 62 | $tops () { 63 | return top.sort((item1, item2) => item2.frontmatter.top - item1.frontmatter.top) 64 | }, 65 | $posts () { 66 | return posts 67 | }, 68 | $tags () { 69 | return tagsMap 70 | }, 71 | $categorys () { 72 | return categorysMap 73 | } 74 | } 75 | }) 76 | } 77 | 78 | export default { install } 79 | -------------------------------------------------------------------------------- /.vuepress/theme/enhance/optionHandle.js: -------------------------------------------------------------------------------- 1 | const install = (Vue, { themeConfig }) => { 2 | const TAGS = '/tags/' 3 | const ROOT = '/' 4 | 5 | const navs = themeConfig.nav 6 | 7 | Vue.options = Vue.options || {} 8 | 9 | const tagsOption = { 10 | useTag: themeConfig.tags, 11 | path: TAGS 12 | } 13 | 14 | const rootOption = { 15 | path: ROOT 16 | } 17 | 18 | navs.forEach(nav => { 19 | if (nav.tags && nav.link) { 20 | tagsOption.path = nav.link 21 | } 22 | if (nav.root && nav.link) { 23 | rootOption.path = nav.link 24 | } 25 | }) 26 | 27 | Vue.options.tags = tagsOption 28 | Vue.options.root = rootOption 29 | 30 | Vue.mixin({ 31 | computed: { 32 | $tagOptions() { 33 | return Object.assign({}, tagsOption) 34 | }, 35 | $rootOptions() { 36 | return Object.assign({}, rootOption) 37 | } 38 | } 39 | }) 40 | } 41 | 42 | export default { install } 43 | -------------------------------------------------------------------------------- /.vuepress/theme/enhance/routes.js: -------------------------------------------------------------------------------- 1 | const CategoryLayout = () => import('@theme/layouts/CategoryLayout') 2 | 3 | const CATEGORYPATH = '/category/' 4 | 5 | const install = (Vue, { router }) => { 6 | let routes = [] 7 | routes.push({ 8 | path: `${CATEGORYPATH}:category?`, 9 | component: CategoryLayout, 10 | meta: { tag: true } 11 | }) 12 | router.addRoutes(routes) 13 | } 14 | 15 | export default { install } 16 | -------------------------------------------------------------------------------- /.vuepress/theme/enhanceApp.js: -------------------------------------------------------------------------------- 1 | import routes from './enhance/routes' 2 | import mixin from './enhance/mixin' 3 | import optionHandler from './enhance/optionHandle' 4 | import filter from './enhance/filter.js' 5 | 6 | export default ({ Vue, router, siteData }) => { 7 | const { themeConfig, pages } = siteData 8 | Vue.use(mixin, { pages }) 9 | Vue.use(optionHandler, { themeConfig }) 10 | Vue.use(routes, { router, themeConfig }) 11 | Vue.use(filter) 12 | } 13 | -------------------------------------------------------------------------------- /.vuepress/theme/global-components/Badge.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 45 | -------------------------------------------------------------------------------- /.vuepress/theme/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | // Theme API. 4 | module.exports = (options, ctx) => ({ 5 | alias () { 6 | const { themeConfig, siteConfig } = ctx 7 | // resolve algolia 8 | const isAlgoliaSearch = ( 9 | themeConfig.algolia 10 | || Object.keys(siteConfig.locales && themeConfig.locales || {}) 11 | .some(base => themeConfig.locales[base].algolia) 12 | ) 13 | return { 14 | '@AlgoliaSearchBox': isAlgoliaSearch 15 | ? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue') 16 | : path.resolve(__dirname, 'noopModule.js') 17 | } 18 | }, 19 | 20 | plugins: [ 21 | ['@vuepress/active-header-links', options.activeHeaderLinks], 22 | '@vuepress/search', 23 | '@vuepress/plugin-nprogress', 24 | ['container', { 25 | type: 'tip', 26 | defaultTitle: { 27 | '/zh/': '提示' 28 | } 29 | }], 30 | ['container', { 31 | type: 'warning', 32 | defaultTitle: { 33 | '/zh/': '注意' 34 | } 35 | }], 36 | ['container', { 37 | type: 'danger', 38 | defaultTitle: { 39 | '/zh/': '警告' 40 | } 41 | }] 42 | ] 43 | }) 44 | -------------------------------------------------------------------------------- /.vuepress/theme/layouts/404.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 47 | 48 | 57 | -------------------------------------------------------------------------------- /.vuepress/theme/layouts/CategoryLayout.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 94 | 95 | 154 | -------------------------------------------------------------------------------- /.vuepress/theme/layouts/Layout.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 61 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /.vuepress/theme/noopModule.js: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/arrow.styl: -------------------------------------------------------------------------------- 1 | @require './config' 2 | 3 | .arrow 4 | display inline-block 5 | width 0 6 | height 0 7 | &.up 8 | border-left 4px solid transparent 9 | border-right 4px solid transparent 10 | border-bottom 6px solid $arrowBgColor 11 | &.down 12 | border-left 4px solid transparent 13 | border-right 4px solid transparent 14 | border-top 6px solid $arrowBgColor 15 | &.right 16 | border-top 4px solid transparent 17 | border-bottom 4px solid transparent 18 | border-left 6px solid $arrowBgColor 19 | &.left 20 | border-top 4px solid transparent 21 | border-bottom 4px solid transparent 22 | border-right 6px solid $arrowBgColor 23 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/code.styl: -------------------------------------------------------------------------------- 1 | .content__default 2 | code 3 | color lighten($textColor, 20%) 4 | padding 0.25rem 0.5rem 5 | margin 0 6 | font-size 0.85em 7 | background-color rgba(27,31,35,0.05) 8 | border-radius 3px 9 | .token 10 | &.deleted 11 | color #EC5975 12 | &.inserted 13 | color $accentColor 14 | 15 | .content__default 16 | pre, pre[class*="language-"] 17 | line-height 1.4 18 | padding 1.25rem 1.5rem 19 | margin 0.85rem 0 20 | background-color $codeBgColor 21 | border-radius 6px 22 | overflow auto 23 | code 24 | color #fff 25 | padding 0 26 | background-color transparent 27 | border-radius 0 28 | 29 | div[class*="language-"] 30 | position relative 31 | background-color $codeBgColor 32 | border-radius 6px 33 | .highlight-lines 34 | user-select none 35 | padding-top 1.3rem 36 | position absolute 37 | top 0 38 | left 0 39 | width 100% 40 | line-height 1.4 41 | .highlighted 42 | background-color rgba(0, 0, 0, 66%) 43 | pre, pre[class*="language-"] 44 | background transparent 45 | position relative 46 | z-index 1 47 | &::before 48 | position absolute 49 | z-index 3 50 | top 0.8em 51 | right 1em 52 | font-size 0.75rem 53 | color rgba(255, 255, 255, 0.4) 54 | &:not(.line-numbers-mode) 55 | .line-numbers-wrapper 56 | display none 57 | &.line-numbers-mode 58 | .highlight-lines .highlighted 59 | position relative 60 | &:before 61 | content ' ' 62 | position absolute 63 | z-index 3 64 | left 0 65 | top 0 66 | display block 67 | width $lineNumbersWrapperWidth 68 | height 100% 69 | background-color rgba(0, 0, 0, 66%) 70 | pre 71 | padding-left $lineNumbersWrapperWidth + 1 rem 72 | vertical-align middle 73 | .line-numbers-wrapper 74 | position absolute 75 | top 0 76 | width $lineNumbersWrapperWidth 77 | text-align center 78 | color rgba(255, 255, 255, 0.3) 79 | padding 1.25rem 0 80 | line-height 1.4 81 | br 82 | user-select none 83 | .line-number 84 | position relative 85 | z-index 4 86 | user-select none 87 | font-size 0.85em 88 | &::after 89 | content '' 90 | position absolute 91 | z-index 2 92 | top 0 93 | left 0 94 | width $lineNumbersWrapperWidth 95 | height 100% 96 | border-radius 6px 0 0 6px 97 | border-right 1px solid rgba(0, 0, 0, 66%) 98 | background-color $codeBgColor 99 | 100 | 101 | for lang in $codeLang 102 | div{'[class~="language-' + lang + '"]'} 103 | &:before 104 | content ('' + lang) 105 | 106 | div[class~="language-javascript"] 107 | &:before 108 | content "js" 109 | 110 | div[class~="language-typescript"] 111 | &:before 112 | content "ts" 113 | 114 | div[class~="language-markup"] 115 | &:before 116 | content "html" 117 | 118 | div[class~="language-markdown"] 119 | &:before 120 | content "md" 121 | 122 | div[class~="language-json"]:before 123 | content "json" 124 | 125 | div[class~="language-ruby"]:before 126 | content "rb" 127 | 128 | div[class~="language-python"]:before 129 | content "py" 130 | 131 | div[class~="language-bash"]:before 132 | content "sh" 133 | 134 | div[class~="language-php"]:before 135 | content "php" 136 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/config.styl: -------------------------------------------------------------------------------- 1 | // layout 2 | $contentWidth = 700px 3 | $themeContainerWidth = 1000px 4 | 5 | // responsive breakpoints 6 | $MQNarrow = 959px 7 | $MQMobile = 700px 8 | $MQMobileNarrow = 419px 9 | 10 | // code 11 | $lineNumbersWrapperWidth = 3.5rem 12 | $codeLang = js ts html md vue css sass scss less stylus go java c sh yaml py 13 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/custom-blocks.styl: -------------------------------------------------------------------------------- 1 | .custom-block 2 | .custom-block-title 3 | font-weight 600 4 | margin-bottom -0.4rem 5 | &.tip, &.warning, &.danger 6 | padding .1rem 1.5rem 7 | border-left-width .5rem 8 | border-left-style solid 9 | margin 1rem 0 10 | &.tip 11 | background-color #f3f5f7 12 | border-color #42b983 13 | &.warning 14 | background-color rgba(255,229,100,.3) 15 | border-color darken(#ffe564, 35%) 16 | color darken(#ffe564, 70%) 17 | .custom-block-title 18 | color darken(#ffe564, 50%) 19 | a 20 | color $textColor 21 | &.danger 22 | background-color #ffe6e6 23 | border-color darken(red, 20%) 24 | color darken(red, 70%) 25 | .custom-block-title 26 | color darken(red, 40%) 27 | a 28 | color $textColor 29 | 30 | 31 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/index.styl: -------------------------------------------------------------------------------- 1 | @require './code' 2 | @require './custom-blocks' 3 | @require './arrow' 4 | @require './toc' 5 | @require './config' 6 | 7 | * 8 | margin 0 9 | padding 0 10 | box-sizing: border-box; 11 | 12 | html 13 | font-size 14px 14 | 15 | body 16 | font-family "Times New Roman", STHeiti, serif 17 | -webkit-font-smoothing antialiased 18 | -moz-osx-font-smoothing grayscale 19 | font-size 14px 20 | line-height 1.5 21 | letter-spacing 1px 22 | word-spacing 1px 23 | color $textColor 24 | 25 | .navbar 26 | background-color $bgColor 27 | border-bottom 1px solid $borderColor 28 | 29 | .inner-block 30 | width $themeContainerWidth 31 | margin 0 auto 32 | 33 | @media (max-width: $MQMobile) 34 | .inner-block 35 | width 100% 36 | 37 | .content, .content__default 38 | // text-align justify 39 | line-height: 1.8 40 | h1, h2, h3, h4, h5, h6 41 | margin-top 1.1rem 42 | margin-bottom 0.9rem 43 | &:hover .header-anchor 44 | opacity: 1 45 | p, ul, ol 46 | margin-top: 0.7rem 47 | margin-bottom 0.7rem 48 | 49 | ul, ol 50 | ul, ol 51 | margin-bottom 0 52 | a 53 | border-bottom 1px dashed #ddd 54 | &:hover 55 | text-decoration underline 56 | p.demo 57 | padding 1rem 1.5rem 58 | border 1px solid #ddd 59 | border-radius 4px 60 | img 61 | margin-top 10px 62 | max-width 400px 63 | border-radius 4px 64 | border 1px solid #eee 65 | 66 | a 67 | font-weight 500 68 | color $accentColor 69 | text-decoration none 70 | &:hover 71 | text-decoration: underline; 72 | 73 | p a code 74 | font-weight 400 75 | color $accentColor 76 | 77 | kbd 78 | background #eee 79 | border solid 0.15rem #ddd 80 | border-bottom solid 0.25rem #ddd 81 | border-radius 0.15rem 82 | padding 0 0.15em 83 | 84 | blockquote 85 | font-size .9rem 86 | color #999 87 | border-left .5rem solid #dfe2e5 88 | margin 0.5rem 0 89 | padding .25rem 0 .25rem 1rem 90 | & > p 91 | margin 0 92 | 93 | ul, ol 94 | padding-left 1.2em 95 | 96 | strong 97 | font-weight 600 98 | 99 | h1 100 | font-size 1.6rem 101 | font-family 'Helvetica Neue', Helvetica, Arial, sans-serif 102 | 103 | h2 104 | font-size 1.3rem 105 | font-family 'Helvetica Neue', Helvetica, Arial, sans-serif 106 | 107 | h3 108 | font-size 1.2rem 109 | font-family 'Helvetica Neue', Helvetica, Arial, sans-serif 110 | 111 | h4 112 | font-size: 1.2rem 113 | font-weight normal 114 | 115 | a.header-anchor 116 | font-size 0.85em 117 | float left 118 | margin-left -0.87em 119 | padding-right 0.23em 120 | margin-top 0.125em 121 | opacity 0 122 | &:hover 123 | text-decoration none 124 | 125 | code, kbd, .line-number 126 | font-family source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace 127 | 128 | hr 129 | border 0 130 | border-top 1px solid $borderColor 131 | 132 | table 133 | border-collapse collapse 134 | margin 1rem 0 135 | display: block 136 | overflow-x: auto 137 | 138 | tr 139 | border-top 1px solid #dfe2e5 140 | &:nth-child(2n) 141 | background-color #f6f8fa 142 | 143 | th, td 144 | border 1px solid #dfe2e5 145 | padding .6em 1em 146 | 147 | @require 'mobile.styl' 148 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/mobile.styl: -------------------------------------------------------------------------------- 1 | @require './config' 2 | -------------------------------------------------------------------------------- /.vuepress/theme/styles/toc.styl: -------------------------------------------------------------------------------- 1 | .table-of-contents 2 | .badge 3 | vertical-align middle 4 | -------------------------------------------------------------------------------- /.vuepress/theme/util/index.js: -------------------------------------------------------------------------------- 1 | export const hashRE = /#.*$/ 2 | export const extRE = /\.(md|html)$/ 3 | export const endingSlashRE = /\/$/ 4 | export const outboundRE = /^(https?:|mailto:|tel:)/ 5 | 6 | export const PATHS = ['/', '/article/', '/category.html', '/article/index.html', '/index.html'] 7 | 8 | export function formatDate (date) { 9 | if (!date) { 10 | return '' 11 | } else { 12 | const time = new Date(date) 13 | const temp = (time.getMonth() + 1) 14 | const month = temp < 10 ? '0' + temp : temp 15 | return `${time.getFullYear()}/${month}/${time.getDate()}` 16 | } 17 | } 18 | 19 | export function isArray (object) { 20 | return object instanceof Array 21 | } 22 | 23 | export function archivePostsByCategory (posts, category) { 24 | let postsMap = {} 25 | posts.forEach(item => { 26 | let categorys = item.frontmatter.categorys 27 | if (categorys) { 28 | categorys = (categorys instanceof Array) ? categorys.join(',') : categorys 29 | } else { 30 | categorys = '' 31 | } 32 | 33 | if (category && categorys.indexOf(category) == -1) { 34 | return 35 | } 36 | 37 | let year 38 | if (item.frontmatter.date) { 39 | year = item.frontmatter.date.substring(0, 4) 40 | } else if (item.lastUpdated) { 41 | year = new Date(item.lastUpdated).getFullYear() 42 | } 43 | 44 | if (postsMap[year]) { 45 | postsMap[year].push(item) 46 | } else { 47 | postsMap[year] = [item] 48 | } 49 | }) 50 | return postsMap 51 | } 52 | 53 | export function normalize (path) { 54 | return decodeURI(path) 55 | .replace(hashRE, '') 56 | .replace(extRE, '') 57 | } 58 | 59 | export function getHash (path) { 60 | const match = path.match(hashRE) 61 | if (match) { 62 | return match[0] 63 | } 64 | } 65 | 66 | export function isExternal (path) { 67 | return outboundRE.test(path) 68 | } 69 | 70 | export function isMailto (path) { 71 | return /^mailto:/.test(path) 72 | } 73 | 74 | export function isTel (path) { 75 | return /^tel:/.test(path) 76 | } 77 | 78 | export function ensureExt (path) { 79 | if (isExternal(path)) { 80 | return path 81 | } 82 | const hashMatch = path.match(hashRE) 83 | const hash = hashMatch ? hashMatch[0] : '' 84 | const normalized = normalize(path) 85 | 86 | if (endingSlashRE.test(normalized)) { 87 | return path 88 | } 89 | return normalized + '.html' + hash 90 | } 91 | 92 | export function isActive (route, path) { 93 | const routeHash = route.hash 94 | const linkHash = getHash(path) 95 | if (linkHash && routeHash !== linkHash) { 96 | return false 97 | } 98 | const routePath = normalize(route.path) 99 | const pagePath = normalize(path) 100 | return routePath === pagePath 101 | } 102 | 103 | export function resolvePage (pages, rawPath, base) { 104 | if (base) { 105 | rawPath = resolvePath(rawPath, base) 106 | } 107 | const path = normalize(rawPath) 108 | for (let i = 0; i < pages.length; i++) { 109 | if (normalize(pages[i].regularPath) === path) { 110 | return Object.assign({}, pages[i], { 111 | type: 'page', 112 | path: ensureExt(pages[i].path) 113 | }) 114 | } 115 | } 116 | console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`) 117 | return {} 118 | } 119 | 120 | function resolvePath (relative, base, append) { 121 | const firstChar = relative.charAt(0) 122 | if (firstChar === '/') { 123 | return relative 124 | } 125 | 126 | if (firstChar === '?' || firstChar === '#') { 127 | return base + relative 128 | } 129 | 130 | const stack = base.split('/') 131 | 132 | // remove trailing segment if: 133 | // - not appending 134 | // - appending to trailing slash (last segment is empty) 135 | if (!append || !stack[stack.length - 1]) { 136 | stack.pop() 137 | } 138 | 139 | // resolve relative path 140 | const segments = relative.replace(/^\//, '').split('/') 141 | for (let i = 0; i < segments.length; i++) { 142 | const segment = segments[i] 143 | if (segment === '..') { 144 | stack.pop() 145 | } else if (segment !== '.') { 146 | stack.push(segment) 147 | } 148 | } 149 | 150 | // ensure leading slash 151 | if (stack[0] !== '') { 152 | stack.unshift('') 153 | } 154 | 155 | return stack.join('/') 156 | } 157 | 158 | /** 159 | * @param { Page } page 160 | * @param { string } regularPath 161 | * @param { SiteData } site 162 | * @param { string } localePath 163 | * @returns { SidebarGroup } 164 | */ 165 | export function resolveSidebarItems (page, regularPath, site, localePath) { 166 | const { pages, themeConfig } = site 167 | 168 | const localeConfig = localePath && themeConfig.locales 169 | ? themeConfig.locales[localePath] || themeConfig 170 | : themeConfig 171 | 172 | const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar 173 | if (pageSidebarConfig === 'auto') { 174 | return resolveHeaders(page) 175 | } 176 | 177 | const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar 178 | if (!sidebarConfig) { 179 | return [] 180 | } else { 181 | const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig) 182 | return config 183 | ? config.map(item => resolveItem(item, pages, base)) 184 | : [] 185 | } 186 | } 187 | 188 | /** 189 | * @param { Page } page 190 | * @returns { SidebarGroup } 191 | */ 192 | function resolveHeaders (page) { 193 | const headers = groupHeaders(page.headers || []) 194 | return [{ 195 | type: 'group', 196 | collapsable: false, 197 | title: page.title, 198 | path: null, 199 | children: headers.map(h => ({ 200 | type: 'auto', 201 | title: h.title, 202 | basePath: page.path, 203 | path: page.path + '#' + h.slug, 204 | children: h.children || [] 205 | })) 206 | }] 207 | } 208 | 209 | export function groupHeaders (headers) { 210 | // group h3s under h2 211 | headers = headers.map(h => Object.assign({}, h)) 212 | let lastH2 213 | headers.forEach(h => { 214 | if (h.level === 2) { 215 | lastH2 = h 216 | } else if (lastH2) { 217 | (lastH2.children || (lastH2.children = [])).push(h) 218 | } 219 | }) 220 | return headers.filter(h => h.level === 2) 221 | } 222 | 223 | export function resolveNavLinkItem (linkItem) { 224 | return Object.assign(linkItem, { 225 | type: linkItem.items && linkItem.items.length ? 'links' : 'link' 226 | }) 227 | } 228 | 229 | /** 230 | * @param { Route } route 231 | * @param { Array | Array | [link: string]: SidebarConfig } config 232 | * @returns { base: string, config: SidebarConfig } 233 | */ 234 | export function resolveMatchingConfig (regularPath, config) { 235 | if (Array.isArray(config)) { 236 | return { 237 | base: '/', 238 | config: config 239 | } 240 | } 241 | for (const base in config) { 242 | if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) { 243 | return { 244 | base, 245 | config: config[base] 246 | } 247 | } 248 | } 249 | return {} 250 | } 251 | 252 | function ensureEndingSlash (path) { 253 | return /(\.html|\/)$/.test(path) 254 | ? path 255 | : path + '/' 256 | } 257 | 258 | function resolveItem (item, pages, base, groupDepth = 1) { 259 | if (typeof item === 'string') { 260 | return resolvePage(pages, item, base) 261 | } else if (Array.isArray(item)) { 262 | return Object.assign(resolvePage(pages, item[0], base), { 263 | title: item[1] 264 | }) 265 | } else { 266 | if (groupDepth > 3) { 267 | console.error( 268 | '[vuepress] detected a too deep nested sidebar group.' 269 | ) 270 | } 271 | const children = item.children || [] 272 | if (children.length === 0 && item.path) { 273 | return Object.assign(resolvePage(pages, item.path, base), { 274 | title: item.title 275 | }) 276 | } 277 | return { 278 | type: 'group', 279 | path: item.path, 280 | title: item.title, 281 | sidebarDepth: item.sidebarDepth, 282 | children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)), 283 | collapsable: item.collapsable !== false 284 | } 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | --- 4 | ## features 5 | - [X] 文章分类功能 6 | - [X] 打赏模块 7 | - [X] 按年归档 8 | - [X] 文章置顶 9 | - [X] 文章创建时间支持 10 | - [X] 文章阅读量统计与评论 11 | - [X] 更好的移动端阅读效果 12 | - [X] RSS订阅 13 | - [X] 文章设置密码 14 | -------------------------------------------------------------------------------- /article/JS进制转换.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | categorys: [javascript] 4 | tags: [进制转换] 5 | date: 2019/05/05 6 | title: javascript的进制转换-2进制、8进制、10进制、16进制互相转换 7 | excerpt: javascript的进制转换-2进制、8进制、10进制、16进制互相转换的一些方法与技巧 8 | --- 9 | 10 | ## 10进制转其他进制 11 | ``` javascript 12 | // 10进制转其他进制 13 | var x = 110 14 | console.log(x.toString(8)) 15 | console.log(x.toString(2)) 16 | console.log(x.toString(16)) 17 | ``` 18 | 19 | ## 其他进制转10进制 20 | 21 | ``` javascript 22 | // 其他进制转10进制 23 | var x = '110' 24 | console.log(parseInt(`${x}`, 2)) // 110此时是2进制数字符串 25 | console.log(parseInt(`${x}`, 8)) // 110此时是8进制数字符串 26 | console.log(parseInt(`${x}`, 16)) // 110此时是16进制数字符串 27 | ``` 28 | -------------------------------------------------------------------------------- /article/about/关于我.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | date: 2019/04/23 4 | categorys: ['成长'] 5 | tags: ['vuepress'] 6 | title: '我为什么要做这个博客' 7 | excerpt: 感觉自己一直以来的生活没有起伏,也没有波折,没有尝过很大的欣喜,也有没体会过彻骨的悲伤。 8 | --- 9 | 10 | ## 今年我给自己定了个目标 11 | 12 | 毕业了也有一段时间。 13 | 14 | 感觉自己一直以来的生活没有起伏,也没有波折,没有尝过很大的欣喜,也有没体会过彻骨的悲伤。 15 | 16 | 而且,一直以来都陷入了一个怪圈当中,就是 **“人这一生很没意义”**。产生这个想法的根源在于,每当想到总有死亡的这一天的时候,我总会陷入无尽的虚无当中。这种虚无感来自于我是一个明确的无神论者,而基于此的理智让我对死亡后那种无意识的感觉非常害怕,就像陆游的一句诗所描述的那样 - **“死去元知万事空”**。 17 | 18 | 这种感觉常常会让我对生活索然无味。 19 | 20 | 而且,更让我一直以来感到绝望的是,我发现我是一个没有梦想的人。简单来说,就是我找不到自己真正喜欢做的事情。当然,这不是一件稀奇的事情。大部分的人都没有可以称得上是梦想的梦想。但这对我来说,无疑是对我的雪上加霜。这样的感觉常常会让我陷入一段时间的低迷。 21 | 22 | 被这种低迷的情绪带着走的同时,也有一些来自生活中的压力。这个压力并不来源于收入的情况或者生活的条件。更多的是作为一个俗人内心的争强与不服。 23 | 24 | 有了上面的心理斗争之后,我决定先试着分享一些东西,无论是有关技术的还是其他的东西的。 25 | 26 | 走起来,总是没错的。 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /article/hello.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | categorys: [个人博客] 4 | tags: [测试] 5 | date: 2019/04/21 6 | title: 这是测试帖,用来测试这个博客支持的样式。 7 | excerpt: 简单完成了这个博客的搭建,这是一篇测试博客样式的文章。博客已经开源,欢迎 `github` 上 `star` 一下 8 | --- 9 | ## 这是H2标签 10 | 这是一个 P 标签的内容,P 标签的 `margin-bottom` 的值是 `0.6rem` 。 11 | 12 | 这是另一个 P 标签的内容。为了填充内容,下面准备了一段话。 13 | 14 | 这是被历史遗忘的一代,没有大战争,没有经济大恐慌,没有目的,只有内心之间的斗争。我们大部分都一样,都会感到痛苦,都会遭遇生活的混乱琐碎,都会认识到生活的复杂,都没有没有生活的答案,都无法理解自己所为之奋斗的目标究竟是什么,上学,工作,恋爱,结婚,生子,生老病死,一切都是按部就班。在一个没有变革的平庸时代,缺乏精神领袖而丧失灵魂皈依的源动力,麻木地饰演自己的社会角色,忠诚地履行自己的社会责任。 15 | 16 | ## 这是H2标签 17 | 这是一个有序列表 18 | 1. 列表一的内容 19 | - 内嵌的无序列表 20 | - 内嵌的无序列表 21 | - 内嵌的无序列表 22 | 2. 列表二的内容 23 | 3. 这一段的内容比较长,这一段的内容比较长,这一段的内容比较长,这一段的内容比较长,这一段的内容比较长,这一段的内容比较长,这一段的内容比较长。 24 | 25 | ## 这是一段代码的样式 26 | ```javascript 27 | export function isActive (route, path) { 28 | const routeHash = route.hash 29 | const linkHash = getHash(path) 30 | if (linkHash && routeHash !== linkHash) { 31 | return false 32 | } 33 | const routePath = normalize(route.path) 34 | const pagePath = normalize(path) 35 | return routePath === pagePath 36 | } 37 | ``` 38 | 39 | ## 这是表格的样式 40 | | name | age | name | age | 41 | | ---------- | --- | ---------- | --- | 42 | | LearnShare | 12 | LearnShare | 12 | 43 | | Mike | 32 | LearnShare | 12 | 44 | 45 | ## 这是一张图片 46 | ![南京李志](../images/lizhi.png) 47 | 48 | ## 参考 49 | [1] [测试下链接](https://github.com/ChangMM) 50 | 51 | -------------------------------------------------------------------------------- /article/mysql设置密码.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | categorys: [数据库] 4 | tags: [mysql] 5 | date: 2019/04/24 6 | title: 在linux上安装mysql(5.7.25版本)后初始化密码。 7 | excerpt: 这个问题网上有很多文章,提供了很多种解法,但大部分都是不能用的,极有可能是版本的问题,由于我没在这方面研究很深,也没有深究,下面只是提供一个可行的方法。 8 | --- 9 | 使用 `sudo apt install mysql-server` 方法安装的 MySQL 服务,安装之后没有临时密码的日志,想着直接修改root密码,但是尝试了很多网上的方法,但是都无法生效,包括 10 | - `mysqld-safe --skip-grant-tables` 启动服务,然后修改密码 11 | - `mysql_secure_installation` 命令引导修改密码 12 | - `mysqladmin` 命令 13 | 14 | 最后终于找到一个正确修改root密码的方法,记录如下: 15 | 16 | ## 环境 17 | - linux 18 | - mysql 5.7.25版本 19 | 20 | ## 方法 21 | 22 | ### 1. 输出安装时自动生成的 `debian.cnf` 文件内容 23 | 24 | ```bash 25 | $ sudo cat /etc/mysql/debian.cnf 26 | ``` 27 | 28 | ### 2. 使用文件中的 user 段的 `debian-sys-maint` 用户进行登录 29 | 30 | ```bash 31 | $ mysql -udebian-sys-maint -p 32 | Enter password: // 这里输入上面文件内的password段的值 33 | ``` 34 | 35 | ### 3. 修改root用户的插件和密码 36 | 37 | > 此处一定要记得改plugin的值为 `mysql_native_password` 38 | ```bash 39 | mysql> UPDATE mysql.user SET plugin="mysql_native_password", authentication_string=PASSWORD("password") WHERE user="root"; 40 | ``` 41 | 如果上一步骤中出现密码过于简单无法修改的情况,可以先将 `validate_password_policy` 的值设置为0或者LOW。 42 | 43 | ```bash 44 | mysql> SET GLOBAL validate_password_policy=0; 45 | ``` 46 | ### 4. 重启mysql就可以使用新设置的密码进行登录了 47 | ```bash 48 | sudo service mysql restart 49 | ``` 50 | -------------------------------------------------------------------------------- /article/product/毕方铺网站简介.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | categorys: [产品] 4 | tags: [网盘搜索, 搜索引擎] 5 | top: true 6 | title: 一个百度网盘搜索引擎 7 | excerpt: 详情请查看 https://www.bifangpu.com 8 | --- 9 | 10 | 详情请查看 [https://www.bifangpu.com](https://www.bifangpu.com) 11 | 12 | -------------------------------------------------------------------------------- /article/为什么做个电子书网站.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | categorys: [产品] 4 | tags: [电子书下载] 5 | top: true 6 | date: 2019/05/12 7 | title: 我为什么要做个电子书下载网站? 8 | excerpt: 我自己其实比较喜欢阅读纸质书,同时自己也买了上百本书了。但是,平时上班背本书还是太重了,尤其是在地铁上,阅读电子书的场景还是挺多的。 9 | --- 10 | 我自己其实比较喜欢阅读纸质书,同时自己也买了上百本书了。但是,平时上班背本书还是太重了,尤其是在地铁上或者是在公司中午午休的时候,阅读电子书的场景还是挺多的。 11 | 12 | 对于我而言,想下载某一本电子书的时候,找到这个资源不是一件难事,往往可以搜索出很多结果。尤其对于技术类的电子书,CSDN上面有很多资源。同时我也是CSDN的付费用户。 13 | ![](https://cdn.iizhi.cn/blog/csdn-jifen.png) 14 | 15 | 但比较难的是,从这么多搜索结果选出比较好的版本不是一件容易的事情。尤其是想找到带有 `目录` 的 `非扫描` 的版本。 16 | ![](https://cdn.iizhi.cn/blog/csdn-result.png) 17 | 18 | 在经历过几次之后,我决定做这么一个[网站](https://www.Iizhi.cn/book),上面的资源都是我能找到的最好的版本。 19 | 20 | 而且都是该类型中豆瓣排名靠前的书,基本覆盖了当前类别的比较好的书。也算是一个参考书单之类的建议。 21 | 22 | -------------------------------------------------------------------------------- /article/关于我.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | date: 2019/04/23 4 | categorys: ['成长'] 5 | tags: ['vuepress'] 6 | title: '我为什么要做这个博客' 7 | excerpt: 感觉自己一直以来的生活没有起伏,也没有波折,没有尝过很大的欣喜,也有没体会过彻骨的悲伤。 8 | --- 9 | 10 | ## 今年我给自己定了个目标 11 | 12 | 毕业了也有一段时间。 13 | 14 | 感觉自己一直以来的生活没有起伏,也没有波折,没有尝过很大的欣喜,也有没体会过彻骨的悲伤。 15 | 16 | 而且,一直以来都陷入了一个怪圈当中,就是 **“人这一生很没意义”**。产生这个想法的根源在于,每当想到总有死亡的这一天的时候,我总会陷入无尽的虚无当中。这种虚无感来自于我是一个明确的无神论者,而基于此的理智让我对死亡后那种无意识的感觉非常害怕,就像陆游的一句诗所描述的那样 - **“死去元知万事空”**。 17 | 18 | 这种感觉常常会让我对生活索然无味。 19 | 20 | 而且,更让我一直以来感到绝望的是,我发现我是一个没有梦想的人。简单来说,就是我找不到自己真正喜欢做的事情。当然,这不是一件稀奇的事情。大部分的人都没有可以称得上是梦想的梦想。但这对我来说,无疑是对我的雪上加霜。这样的感觉常常会让我陷入一段时间的低迷。 21 | 22 | 被这种低迷的情绪带着走的同时,也有一些来自生活中的压力。这个压力并不来源于收入的情况或者生活的条件。更多的是作为一个俗人内心的争强与不服。 23 | 24 | 有了上面的心理斗争之后,我决定先走着看看,先慢慢的迈出一步。 25 | 26 | 所以我给自己定了个目标 —— 凭借自己的能力赚到 100 万。 27 | 28 | 我不知道,赚到100万之后该干嘛,只是觉得自己改迈出去一点了。到我写这篇文章的时候,今年已经快过半。我也短短续续产生了很多想法,并做了一些事情。包括这个论坛,以及我的[个人网站](https://www.iizhi.cn)上面的东西。 29 | 30 | 其实,在我自己的idea list中还有十几个想法亟待实现。 31 | 32 | 写着篇文章的目的是想邀请你来作为一个见证者。见证我从0-100万的这一路。 33 | 34 | 毕竟一个人的战斗永远是孤独的。 35 | 36 | ## 见证 37 | 可以加我微信,不过请备注【博客】不然不会通过。 38 | 39 | -------------------------------------------------------------------------------- /article/动物森友会.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | categorys: [游戏] 4 | tags: [游戏] 5 | date: 2020/04/01 6 | title: 动物森友会进群 7 | excerpt: 动物森友会进群 8 | --- 9 | 10 | 扫码加我微信,拉你进群! 11 | 12 | ![二维码](https://res.oodcd.cn/zhi/wechat.jpg) 13 | ![二维码](https://res.oodcd.cn/zhi/qun.jpg) 14 | 15 | 16 | -------------------------------------------------------------------------------- /article/基于Vuepres搭建个人博客.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: sakamoto 3 | date: 2019/04/24 4 | categorys: ['个人博客', '教程'] 5 | tags: ['vuepress'] 6 | title: '基于vuepress搭建个人博客' 7 | excerpt: 本篇文章主要开源这个博客的源代码,并记录了基于vuepress的一些自定义主题开发过程中的一些问题。 8 | --- 9 | ## 博客支持功能 10 | - [x] 文章分类功能 11 | - [x] 打赏模块 12 | - [x] 按年归档 13 | - [x] 文章置顶 14 | - [x] 文章创建时间支持 15 | - [x] 文章阅读量统计与评论 16 | - [x] 更好的移动端阅读效果 17 | - [x] RSS订阅 18 | - [x] 文章设置密码 19 | 20 | ## 开发环境 21 | - [VuePress 1.x](https://v1.vuepress.vuejs.org/zh/guide/) 22 | - Node.js v10.8.0 23 | 24 | ## 本博客的开源代码地址 25 | - [Github](https://github.com/ChangMM/blog) 26 | 27 | ## 开始 28 | 具体的开发细节官网上已经说得很详细了,而且代码已经开源,所以这里不在说具体的细节,主要列举开发过程中遇到的一些问题。 29 | 30 | ## 如何添加分类的路由 31 | 只需要在 `enhanceApp.js` 中获取 `Vue` 以及 `router` 这两个对象,然后像在开发Vue项目中给应用添加正常的路由即可。 32 | 33 | 代码如下: 34 | ```javascript 35 | const CategoryLayout = () => import('@theme/layouts/CategoryLayout') 36 | const CATEGORYPATH = '/category/' 37 | const install = (Vue, { router }) => { 38 | let routes = [] 39 | routes.push({ 40 | path: `${CATEGORYPATH}:category?`, 41 | component: CategoryLayout, 42 | meta: { tag: true } 43 | }) 44 | router.addRoutes(routes) 45 | } 46 | export default { install } 47 | ``` 48 | 49 | ## 文章创建时间支持 50 | `VuePress` 默认是没有文章的创建时间这个字段的,其实实现这个功能也比较简单,就是通过 `Vuepress` 提供的 `Plugin` 的功能。 51 | 52 | 需要知道的是, vuepress 中的 plugin 是运行在 node 的环境中的。所以只需要,利用 node 提供的 `fs.statSync` 这个api即可。 53 | 54 | 具体代码如下: 55 | 56 | ``` javascript 57 | const fs = require('fs') 58 | module.exports = (options = {}, context) => ({ 59 | extendPageData ($page) { 60 | $page.publishDate = getFilePublishDate($page._filePath) 61 | } 62 | }) 63 | function getFilePublishDate (filePath) { 64 | let publishDate 65 | try { 66 | publishDate = fs.statSync(filePath).birthtime 67 | } catch (e) { /* do not handle for now */ } 68 | return publishDate 69 | } 70 | ``` 71 | 72 | 只需要在 vuepress 的 `config.js` 中加载这个plugin即可。 73 | ```javascript 74 | ··· 75 | plugins: [ 76 | require('./plugins/page-publish-date.js') 77 | ], 78 | ··· 79 | ``` 80 | ## 文章阅读量统计与评论 81 | 文章的阅读量与统计功能其用的是 `Valine` 这个库。好像只有这个库可以同时有这两个功能,所以就选了这个。 82 | 83 | 实现起来也是比较简单的,但是中间遇到了两个问题。 84 | ### 1. vuepress 无法编译成功 85 | ```javascript 86 | window.AV = require('leancloud-storage') 87 | const Valine = require('valine') 88 | new Valine({ 89 | el:'#comment', 90 | ... 91 | }) 92 | ``` 93 | 如果按照下面的方式初始化评论组件的话,在本地dev模式是可以通过的,但是 `npm run build` 的时候会提示 `window is not undefied` 的错误,即使在评论组件加上 VuePress 提供的 `ClientOnly` 的标识符也会出现这个问题。 94 | 95 | 最后的解决办法是,以 `script` 标签的方式引入 leancloud-storage 和 valine 两个库。并在评论组件中轮询检查这两个库是否加载完成,在加载完成之后在初始化评论组件。 96 | 代码如下: 97 | ```javascript 98 | 131 | ``` 132 | 133 | ### 2.按照教程配置好后,发现文章切换时,评论内容并没有切换 134 | 这个主要是由于 `Valine` 这个库在初始化全局对象时,如果没有传入path这个属性,其内部会缓存当前页面的 path。解决的办法也很简单,只要在传 path 的时候指定的值即可,也即👆上面代码中的 `window.location.pathname`。 135 | 136 | ## 一些其他问题 137 | 其实在开发过程中还是有一些其他的问题,比如 分类的路由通过首页页面点进去可以直接访问,但是如果直接在浏览器的地址栏输入地址的话 Nginx 会索引不到相应的文件 提示 404 的错误。 138 | 139 | 这个问题的话,只需要在 `nginx` 的配置中添加下面👇的配置即可 140 | ```Nginx 141 | location / { 142 | try_files $uri $uri/ /index.html /404.html; 143 | } 144 | ``` 145 | 146 | ## 最后 147 | 如果还有其他问题的话,可以加我微信好友,请备注【vuepress】不然不会通过的。 148 | 149 | -------------------------------------------------------------------------------- /images/lizhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChangMM/blog/cb06f7b1b42f36c42c3249627db943320d990e96/images/lizhi.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "vuepress dev .", 4 | "build": "vuepress build ." 5 | }, 6 | "devDependencies": { 7 | "@vuepress/plugin-google-analytics": "^1.0.0-alpha.47", 8 | "@vuepress/plugin-pagination": "^1.0.0-alpha.48", 9 | "axios": "^0.19.2", 10 | "vuepress": "^1.0.0-alpha.47", 11 | "vuepress-plugin-rss": "^2.0.0" 12 | }, 13 | "dependencies": { 14 | "leancloud-storage": "^3.13.0", 15 | "valine": "^1.3.6" 16 | } 17 | } 18 | --------------------------------------------------------------------------------