vuepress主題改造-標籤雲的改造(2)

前言

上一章已經講了 vuepress 主題如何實現繼承,這樣咱們能夠任意修改默認主題的任何組件及樣式了。咱們知道 vuepress 是沒法自動根據咱們 markdown 文件中的html

---
tags:
- js
- vue
---
複製代碼

生成標籤雲的頁面的,而一個博客,標籤在其中有知識分類及導航功能,是必不可少的一環,下面帶領你們來改造一下默認主題讓它能支持自動生成標籤雲頁面vue

第一步配置的修改

既然是主題,就要提供可定製化,若是有人不須要 tag 功能,那也須要知足需求,打開 config.js 文件,修改其中的配置git

themeConfig: {
    ...
    tags:"/tags",
    ...
    nav: [
    ...
        {
            text:"標籤雲",
            link:'/tags/',
            tags:true
        },
    ...
    ]
    ...
}
複製代碼

我這樣配置的緣由是 nav 是給頭部目錄添加菜單,tags:"/tags"是定義標籤路由路徑,這樣無論個人標籤頁定義成什麼名字,都能導航到正確的位置。github

第二步文件夾創建

因爲 vuepress 是根據 markdown 文件生成的路由,因此想要生成一個標籤的頁面也必須創建一個 markdown 文件。 在.vuepress 文件夾下創建 tags 文件夾,其中新建 README.md 文件。 重啓項目 可看到web

啓動圖片

第三步新建 Tags 組件

在 docs/.vuepress/theme/components 下新建 Tags.vue 文件。 爲了使頁面自動集成 tag 組件,須要修改 Layout.vue 組件,上一節咱們講過要修改默認主題能夠用組件的繼承,如今把默認主題的 Layout 組件複製到 docs/.vuepress/theme/layouts 目錄下(若是不知道如何複製默認主題的 Layout 請看上一節),修改其中的json

...
    </Sidebar>
    <!-- 側邊欄 -->
    <Home v-if="$page.frontmatter.home"/>
    <!-- 若是md文件中有 home:true 就使用該組件 -->
    <Tags v-else-if="tags"/>
    <Page
        v-else
        :sidebar-items="sidebarItems"
        >
            <slot
            name="page-top"
            slot="top"
            />
            <slot
            name="page-bottom"
            slot="bottom"
            />
    </Page>
...
複製代碼

在script中對tags變量的判斷數組

export default {
  ...
  data() {
    return{
      ...
      tags:false
    }
  },
  ...
  created(){
    this.checkTags()
  }
  ...
  checkTags() {
      path=this.$route.path
      let tags = this.$site.themeConfig.nav.filter(v => v.tags); //判斷tags
      if (tags[0].link === path) {
        this.tags = true;
        this.$page.frontmatter.sidebar = false; //tags不須要側標欄
      } else {
        this.tags = false;
      }
      //判斷是不是分類頁面
      let type = this.$page.frontmatter.type;

      if (type === "classify") {
        this.type = "classify";
        this.$page.frontmatter.sidebar = false; //tags不須要側標欄
      } else {
        this.type = "";
      }
      if (this.$page.frontmatter.defaultHome) {
        this.$page.frontmatter.sidebar = false; //主頁不須要側標欄
      }
    }
  }
複製代碼

引入 Tags 組件,其中的 tags 是判斷當前頁面路由 tags 是否爲 true,這是 config.js 中配置的選項。 再新建的 Tags.vue 文件中加入如下內容,這是我定義的tag組件,大家能夠根據個人組件自行修改bash

<template>
  <div>
    <div class="content default"></div>
    <div class="tag">
      <div class="items">
        <span
          v-for="taginfo in tags"
          :style="{backgroundColor:color()}"
          @click="change(taginfo.tag)"
          :class="taginfo.tag===tg?'active':''"
        >{{taginfo.tag}}({{taginfo.number}})</span>
      </div>
      <div class="article-list">
        <Article v-for="tag in info" :tag="tag" :tg="tg" @turnTo="change"/>
      </div>
    </div>
  </div>
</template>

<script>
import Article from "@theme/components/Article.vue";
export default {
  components: {
    Article
  },
  data() {
    return {
      info: [],
      tg: ""
    };
  },
  computed: {
    tags() {
      //核心代碼,整合markdown中tags的數目
      let allTags = [];
      this.$site.pages.forEach(v => {
        if (v.frontmatter.tags) {
          allTags.push(v.frontmatter.tags);
        } else if (v.frontmatter.tag) {
          allTags.push(v.frontmatter.tag);
        }
      });
      allTags = allTags.join(",").split(",");
      let flatTags = Array.from(new Set(allTags));
      return flatTags.reduce((res, v) => {
        let o = {};
        o.tag = v;
        o.number = allTags.filter(value => value === v).length;
        res.push(o);
        return res;
      }, []);
    }
  },
  methods: {
    change(tag) {
      //點擊標籤下面文章顯示對應的內容
      this.tg = tag;
      this.info = this.$site.pages.filter(v => {
        let tags = v.frontmatter.tags;
        if (tags) {
          return tags.some(v => v === tag);
        }
      });
    },
    color() {
      // 標籤button顏色
      let colors = [
        "#3498DB",
        "#3EAF7C",
        "#5CBBF6",
        "#f5A28E",
        "#f2AC3B",
        "#FA6551",
        "#C68CE0"
      ];
      return colors[parseInt(Math.random() * colors.length)];
    }
  },
  mounted() {
    //當路由?tag='xxx'時能自動跳轉到對應內容
    let tag = this.$route.query.tag;
    if (tag) {
      this.change(tag);
    }
  }
};
</script>

<style lang='stylus' scoped>
.tag {
  max-width: 46.5rem;
  margin: 0 auto;
  padding: 0 2.5rem;

  .items {
    margin-bottom: 2rem;

    span {
      vertical-align: middle;
      cursor: pointer;
      margin: 0.5rem 0.5rem 0.2rem;
      padding: 0.4rem 0.7rem;
      display: -webkit-inline-box;
      display: -ms-inline-flexbox;
      display: inline-flex;
      border-radius: 0.2rem;
      background: #fff;
      color: #fff;
      font-size: 1rem;
      box-shadow: 0 1px 0.25rem 0 hsla(0, 0%, 57%, 0.21);
      transition: all 0.3s;
      background-color: red;

      &.active {
        transform: scale(1.2);
      }

      &:hover {
        transform: scale(1.2);
      }
    }
  }
}
</style>

複製代碼

其中 Article 組件是標籤中顯示文章內容的部分的組件,你們可自行定義組件及樣式,我貼上本身的 Article 組件markdown

<template>
  <div class="abstract">
    <div class="abstract-item">
      <div class="text-hover">
        <router-link :to="tag.path">{{tag.title}}</router-link>
      </div>
      <!---->
      <div class="abstract">
        <div class="tip custom-block" v-if="tag.excerpt">
          <!-- <p class="custom-block-title">{{tag.title}}</p>
            <p>我的一些自動的 vs code 配置(Settings.json)</p>
            <ul>
            <li>VsCode 經常使用插件配置</li>
          </ul>-->
          <div v-html="tag.excerpt"></div>
        </div>
      </div>
      <div class="details-btn">
        <router-link :to="tag.path">
          <div data-v-e422eb16 class="v-btn">
            <i data-v-e422eb16 class="what"></i>
            閱讀全文
          </div>
        </router-link>
      </div>
      <div class="v-divider"></div>
      <div class="article-info article-info-item">
        <i class="what">
          <em v-if="tag.lastUpdated">{{tag.lastUpdated}}</em>
        </i>
        <i class="what" v-for="t in tag.frontmatter.tags">
          <em class="text-item active" v-if="t==tg">{{t}}</em>
          <em class="text-item" v-else @click="$emit('turnTo',t)">{{t}}</em>
        </i>
        <!-- <i
            class="iconfont h-classify article-info-item"
            class="what"
            >
            <em class="text-item">IDE</em>
        </i>-->
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    tag: {}, //索引到的數據
    tg: ""
  }
};
</script>

<style lang="stylus" scoped>
$color = #3eaf7c;

.abstract {
  margin-top: 1rem;
  width: 100%;

  .abstract-item {
    margin: 0 auto 1.2rem;
    padding: 1rem 1.2rem;
    width: 100%;
    overflow: hidden;
    border-radius: 0.3rem;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    -webkit-transition: all 0.3s;
    transition: all 0.3s;
    -webkit-box-shadow: 0 0.25rem 1.2rem 0 hsla(0, 0%, 57%, 0.21);
    box-shadow: 0 0.25rem 1.2rem 0 hsla(0, 0%, 57%, 0.21);
    background-color: #fff;
    position: relative;

    .abstract {
    }

    .text-hover {
      position: relative;
      font-size: 1.2rem;
      line-height: 2rem;
      display: inline-block;

      a {
        &:after {
          content: '';
          position: absolute;
          width: 101%;
          height: 2px;
          bottom: 0;
          left: 0;
          background-color: $color;
          visibility: hidden;
          -webkit-transform: scaleX(0);
          transform: scaleX(0);
          -webkit-transition: 0.3s ease-in-out;
          transition: 0.3s ease-in-out;
        }

        &:hover:after {
          visibility: visible;
          -webkit-transform: scaleX(1);
          transform: scaleX(1);
        }
      }
    }

    .details-btn {
      text-align: right;
      margin: 0.6rem 0;

      .v-btn {
        display: inline-block;
        font-size: 0.8rem;
        padding: 0.4rem 0.7rem;
        cursor: pointer;
        letter-spacing: 0.1em;
        -webkit-transition: all 0.3s;
        transition: all 0.3s;
        background-color: #efefef;
        color: #2c3e50;
        border-radius: 0.1rem;
        line-height: 1.2;

        &:hover {
          background-color: $color;
          color: #fff;
        }
      }
    }

    .article-info {
      margin-right: 1rem;
      line-height: 1.6rem;
      margin-right: 1rem;
      line-height: 1.6rem;
      font-style: normal;

      .text-item {
        font-weight: 700;
        border: 1px $color;
        font-style: normal;
        margin-left: 0.4rem;
        cursor: pointer;
        background-color: #f6f6f6;
        padding: 0.2rem 0.4rem;

        &.active {
          color: $color;
        }

        &:hover {
          color: $color;
        }
      }
    }

    .v-divider {
      display: block;
      -webkit-box-flex: 1;
      -ms-flex: 1 1 0px;
      flex: 1 1 0px;
      max-width: 100%;
      height: 0;
      max-height: 0;
      border: solid;
      border-width: thin 0 0 0;
      -webkit-transition: inherit;
      transition: inherit;
      border-color: rgb(234, 236, 239);
      margin-top: 0.7rem;
      margin-bottom: 0.7rem;
    }
  }
}

.what {
  font-size: 0.8rem;
  color: rgb(153, 153, 153);
}
</style>

複製代碼

至此,標籤雲頁面已經完成,效果以下 dom

標籤雲效果

第四步 頁面顯示標籤頁及標籤頁跳轉

Page組件是文章顯示的內容組件,若是須要在文章顯示的時候把標籤顯示到文章頭部,就須要改造Page組件。

把默認主題中 components 下的 Page.vue 文件複製到 docs/.vuepress/theme/components 中, 修改其中內容

<slot name="top"/>
<!-- 如下是添加的內容 -->
<section class="tags" v-if="this.$site.themeConfig.tags&&tags&&tags.length>0">
    <!-- tags是this.$page.frontmatter.tags,這是經過vuepress編譯markdown文件中的tags生成的標籤數組。 -->
    <span class="tagPopup" v-for="tag in tags">
        <!-- $site.themeConfig.tags是config.js中配置的tags目錄 -->
        <router-link :to="'/'+$site.themeConfig.tags+'/?tag='+tag" class="tag">{{tag}}</router-link>
    </span>
</section>
<!-- 以上是添加的內容 -->
<Content/>

複製代碼

修改後效果以下

page修改效果

至此,標籤雲的改造大體完成,這裏貼上我改造好的源碼地址:vuepress-theme-reform

查看效果可來到個人博客

相關文章
相關標籤/搜索