建站啦[vuepress blog]

经过三天的学习和尝试,LeeDua终于搭起了人生中第一个博客。关于vuepress的原因在关于中已经说明。下文简单记录一下实现中的一些收获和感想。

# 项目结构

官方文档对vuepress项目结构的说明还是比较清楚的,但还是有几点是我摸索后才明白的。

  • theme文件夹的位置不必是固定的,可以在config.js中theme:folder指定,所以其实文件夹叫什么都可以
  • GlobalLayout.vue必须在theme\layouts下才有效,经过尝试目前在index.js中指定globalLayout无效
  • 使用外部vue component时在enhanceApp.js中注册后即可全局使用
import live2d from 'live2d-vue'
export default ({
    Vue,
    options,
    router,
    siteData
}) => {
    Vue.use(live2d)
}

# 路由映射和页面渲染

  • vuepress默认任何一个文件夹someFolder下如果有README.md则为这个文件夹生成一条路由someFolder,以README.md
  • 可以在md frontmatter中指定layout:vue-component,未指定时使用的是layout.vue而不是folderName.vue
  • blog插件提供了额外的路由聚合功能,即根据frontmatter中的某个prop生成路由/prop/,在该路径下整合所有有此prop的post
  • GlobalLayout
    • 理解blog的UI调用逻辑的难点就只有GlobalLayout,其他都只是标准的vue-components
    • 以下是官网上给出的使用方式,实际上是对GlobalLayout源代码的截取。
<!-- themePath/layouts/GlobalLayout.vue -->
<template>
  <div id="global-layout">
    <header><h1>Header</h1></header>
    <component :is="layout"/>
    <footer><h1>Footer</h1></footer>
  </div>
</template>

<script>
export default {
  computed: {
    layout () {
      if (this.$page.path) {
        if (this.$frontmatter.layout) {
          // You can also check whether layout exists first as the default global layout does.
          return this.$frontmatter.layout
        }
        return 'Layout'
      }
      return 'NotFound'
    }
  }
}
</script>
  • 使用过程中可能导致组件注册的相关问题。对比源代码,容易发现少了检查组件是否已注册的过程。
<template>
  <component :is="layout" />
</template>

<script>
import Vue from 'vue'
import { setGlobalInfo } from '@app/util'
export default {
  name: 'GlobalLayout',
  computed: {
    layout () {
      const layout = this.getLayout()
      setGlobalInfo('layout', layout)
      return Vue.component(layout)
    }
  },
  methods: {
    getLayout () {
      if (this.$page.path) {
        const layout = this.$page.frontmatter.layout
        if (layout && (this.$vuepress.getLayoutAsyncComponent(layout)
          || this.$vuepress.getVueComponent(layout))) {
          return layout
        }
        return 'Layout'
      }
      return 'NotFound'
    }
  }
}
</script>
  • 正确的使用方式如下
import GlobalLayout from '@app/components/GlobalLayout.vue'
export default {
  components: {
    DefaultGlobalLayout: GlobalLayout,
  },
  • 读了源代码后就容易理解GlobalLayout做了什么。GlobalLayout先查frontmatter里是否指定了layout,如果有则使用,如果没有则使用Layout,这也默认使用Layout.vue的原因。

# dynamic layout

改变窗口大小可以发现中间的post的width在不同阈值下跳变,sidebar和小埋也在页面窄到一定程度时就消失,转而由topbar和footer替换。实现起来就是media query多个阈值的调整。

  • 具体实现时sidebar的宽度实际上是动态计算得到的,因为sidebar是fixed的,不能通过float left直接紧挨着post,所以要每次resize时要动态计算post右边缘到页面左边缘的距离作为left的偏移值。
onResize(event) {
  if(this.$refs["pagelist"]==undefined)return;
  let rect = this.$refs["pagelist"].getBoundingClientRect();
  let window_width = window.innerWidth || document.documentElement.clientWidth || 
      document.body.clientWidth;
  let sw = window_width - rect.right - 30;
  this.sidebarWidth = sw;
  if(window_width < 840 && this.isMobileHeaderOpen == false){
    this.isMobileHeaderOpen = true;
  }
  else if(this.isMobileHeaderOpen && window_width > 840){
    this.isMobileHeaderOpen = false;
  }        
}

# font-family

第一次接触font-family。font-family往往由一组不同的字体组成,每种字体对应不同unicode 不同font-weight下的情况。明白这一点就容易进行字体配置了。

# 其他

  • stylus真香,我竟然这么久以来一直不依赖preprocessor写css(太懒,之前听说过也读过sass scss但是以为只是改改语法就没系统学习过),简直就是憨憨
  • 学习了pwa和service-worker的相关概念,发现一个不错的pwa视频系列教程
  • 写这篇博客中发现在vue代码块前加-会导致vue stack exceed limit网页崩溃,算是一个bug?
  • vuepress的热刷新
    • 需要手动重启的场景其实都是vuepress build过程中的一次性步骤,即只有在build时才会做的事。如生成路由、抽取frontmatter分类、增删或重命名文件(根据功能容易想象vuepress内部维护了文件与页面、component相对引用的映射结构),以及某些情况下由于某些插件的版本冲突可能导致热刷新失败
  • 背景的实现
    • background-image是不能设置opacity的
    • 一种实现是body::before设置img并设置opacity
    • 我使用的实现是使用blend
  background-image url('/bg_h4.png')
  background-repeat no-repeat
  background-size cover
  background-position center
  background-attachment fixed
  background-color rgba(#fff,0.97)
  background-blend-mode lighten
  • 最后,附上blog的源代码。多余的component和blog插件没用上的功能相关的代码并没有删去。vuepress其实提供了extend一个theme的功能但我并没有使用,一是想看看default theme是怎么写的,二是觉得要改的地方比较多,extend还不如直接改方便。