简介

由于本人不是专业的前端,所以写出来的界面可能会稍微有些丑陋,甚至有些地方的写法不是很专业,还请大家见谅

主界面

JS 部分

首先是 js 逻辑部分

我们先在@/http/request.js中定义获取文章信息的方法

// 此处省略 axios 的封装,前面的文章中有
export default {
  getArticles(page, limit) {
    return instance.get(urls.articles, {
      params: {
        page: page,
        limit: limit
      }
    }).then(res => res.data);
  }
}

然后,下面是Home.vue中的 js 部分

<script>
import request from "@/http/request";
export default {
  name: "Home",
  data() {
    return {
      carousel: {
        title: "竹林客栈",
        desc: "分享知识,分享生活,分享感动",
        urls: [
          "https://tvax1.sinaimg.cn/mw1024/bfe05ea9ly1fxgu8jys3fj21hc0u0k0j.jpg",
          "https://tvax1.sinaimg.cn/large/bfe05ea9ly1fxgunx09dtj21hc0u0q81.jpg",
          "https://tvax1.sinaimg.cn/large/bfe05ea9ly1fxgv2t92yyj21hc0u0qb9.jpg"
        ]
      },
      pageInfo: {}
    };
  },
  created() {
    request
      .getArticles(1, 5)
      .then(res => {
        if (res.code === 0) {
          this.pageInfo = res.data;
        } else {
          this.$notify.error({
            title: "提示",
            message: res.msg
          });
        }
      })
      .catch(err => {
        console.log(err);
        this.$notify.error({
          title: "提示",
          message: "网络忙,文章获取失败"
        });
      });
  }
};
</script>

说明:

  • 在 data 中定义 carousel 用于展示轮播图信息,这里先写成固定的,以后我们可以再改成从后端获取
  • data 中的 pageInfo 表示一页文章信息
  • 然后就是 created 函数在实例已创建,模板还未渲染的时候执行,用于获取文章信息,如果出现错误就弹出提示信息

HTML部分

下面就是数据在页面上的展示,基本就是一些 CSS 和 HTML ,需要注意的是:

  • 分类和标签使用了 router-link 标签包裹,这样可以实现点击文字跳转到对应分类或者标签的效果
  • 文章标题使用 router-link 跳转的时候把文章 id 作为路径参数传递过去,这样的话在文章详情页面就可以获取到文章 id ,进而根据文章 id 获取文章信息。
  • 其中在标题的渲染的时候使用了 v-html 而不是 v-text,是为了方便后期实现根据关键字搜索功能(因为根据实现根据关键字搜索功能的时候,可能需要将某些关键字标红,需要设置行间css样式)
  • 文章列表和个人信息部分采用 Element-UI 的分栏布局,详情可参考:https://element.eleme.cn/#/zh-CN/component/layout
<template>
  <div>
    <el-carousel indicator-position="none" height="400px" arrow="nerver" :interval="5000">
      <el-carousel-item v-for="item in carousel.urls" :key="item">
        <div class="item-box">
          <img :src="item" class="carimg" />
          <div class="desc-box">
            <h1>{{ carousel.title }}</h1>
            <p>{{ carousel.desc }}</p>
          </div>
        </div>
      </el-carousel-item>
    </el-carousel>
    <el-row :gutter="20">
      <el-col :span="14" :offset="2">
        <el-card v-for="article in pageInfo.records" :key="article.id">
          <div slot="header">
            <router-link class="main-text" :to="'/post/' + article.id" v-html="article.title"></router-link>
            <div class="article-info">
              <el-tag effect="dark" size="mini">原创</el-tag>
              浏览量:{{article.views}} 分类:
              <router-link
                class="link secondary-text"
                :to="'/category/'+article.category"
              >{{article.category}}</router-link>
            </div>
          </div>
          <div class="tabloid">{{article.tabloid}}</div>
          <i class="el-icon-user-solid article-icon">{{article.author}}</i>
          <i class="el-icon-date article-icon">{{article.gmtCreate}}</i>
          <i class="el-icon-price-tag article-icon">
            <router-link
              class="tag"
              v-for="(tag,index) in article.tags"
              :key="index"
              v-text="tag"
              :to="'/tag/'+tag"
            ></router-link>
          </i>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>个人信息</el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script>
// ......上面已经说过,不再赘述
</script>

<style scoped>
.item-box {
  position: relative;
  width: 100%;
  height: 100%;
}
.carimg {
  width: 100%;
  height: 100%;
  overflow: hidden;
  object-fit: cover;
}
.desc-box {
  position: absolute;
  bottom: 0;
  left: 50%;
  top: 50%;
  width: 500px;
  height: 40px;
  margin-left: -250px;
  margin-top: -20px;
  text-align: center;
}
.el-card {
  margin-top: 20px;
}
.article-info {
  margin-top: 10px;
  color: #909399;
  font-size: 13px;
}
.article-icon,
.article-icon .tag {
  color: #909399;
  font-size: 13px;
  margin-right: 10px;
  text-decoration: none;
}
.article-icon .tag:hover {
  color: #409eff;
  cursor: pointer;
}
.tabloid {
  color: #606266;
  font-size: 14px;
  margin-bottom: 10px;
}
</style>

页面效果

文章列表界面

文章详情

1、在 @/http/request.js 中封装根据 id 获取文章信息的方法

  getArticleByID(id) {
    return instance.get(urls.article + "/" + id).then(res => res.data);
  }

2、新建 Article.vue 用于展示页面详情

<template>
  <el-row>
    <el-col :span="20" :offset="2">
      <el-card>{{article}}</el-card>
    </el-col>
  </el-row>
</template>

<script>
import request from "@/http/request";
export default {
  name: "Article",
  data() {
    return {
      article: {}
    };
  },
  created() {
    request
      .getArticleByID(this.$route.params.id)
      .then(res => {
        if (res.code === 0) {
          this.article = res.data;
        } else {
          this.$notify.error({
            title: "提示",
            message: res.msg
          });
        }
      })
      .catch(err => {
        console.log(err);
        this.$notify.error({
          title: "提示",
          message: "网络忙,文章详情获取失败"
        });
      });
  }
};
</script>

<style scoped>
.el-card {
  margin-top: 15px;
  padding: 20px;
}
</style>

说明:

  • 当组件创建的时候获取文章信息
  • 使用 this.$route.params 可以获取路由的路径参数,即文章 id

3、在路由 @/router/index.js 中注册 Article.vue 组件对应的路由

  {
    path: "/post/:id",
    name: "Article",
    component: () => import("@/views/Article.vue"),
    meta: {
      title: "文章详情",
    },
  },

4、将 markdown 转为 html

markdown 转 html 有很多种方法,可以在前端做转换,也可以在后端转换,这里我们采用前端转换,使用Showdown.js

我们可以使用在项目中导入 js 文件的形式转换,也可以使用大佬封装好的 Vue 组件,这里我们使用一个叫做 VueShowdown 的组件,文档:https://vue-showdown.js.org/zh/guide/

首先,安装 VueShowdown 以及它的插件

npm install vue-showdown
npm install showdown-highlight # 代码高亮插件,只是转化,并没有对应 css
npm install highlight # 引入 highlight.js 主要是想使用,代码高亮的 css 

在 main.js 中引入相应的 css,不然高亮不生效, highlight.js 中自带很多 css 高亮样式,这里我们使用 github 样式

import 'highlight.js/styles/github.css'

在 main.js 中注册组件

import { VueShowdown } from 'vue-showdown'
Vue.component('VueShowdown', VueShowdown)

使用组件:

<template>
  <el-row>
    <el-col :span="20" :offset="2">
      <el-card>
        <VueShowdown
          :markdown="article.content"
          flavor="vanilla"
          :options="{ emoji: true, tables: true }"
          :extensions="extensions"
        />
      </el-card>
    </el-col>
  </el-row>
</template>

说明:

  • options 中配置开启 emoji 表情和表格解析

注意此时的data中的 article需要修改为如下格式,不然会报错。

  data() {
    return {
      article: { content: "" },
      extensions: [showdownHighlight]
    };
  },

此时,我们的markdown可以转换为html,代码也可以高亮了。但是原生的 html 样式有些丑,这个时候,我们就可以使用一个好看的css样式来美化项目,这里我们使用的是github-markdown-css

安装:

npm install github-markdown-css

在main.js中引入,这里这里的 github-markdown.css 和上面引入的 highlight.js/styles/github.css 不同,后者只有高亮效果

import 'github-markdown-css/github-markdown.css';

说明:

  • 这里的css名称以及路径都可以在 node_modules 目录中找到,如下图中 CSS 文件的路径为 github-markdown-css/github-markdown.css 所以在 main.js 中导入的路径就为 github-markdown-css/github-markdown.css

寻找CSS文件的位置

最后,在需要使用该样式的外层加入class="markdown-body"即可

<template>
  <el-row>
    <el-col :span="20" :offset="2">
      <el-card class="markdown-body">
        <h1>{{article.title}}</h1>
        <blockquote>{{'作者:' + article.author + ' | 创建时间:' + article.gmtCreate + ' | 浏览数:' + article.views + ' | 分类:' + article.category + ' | 标签:' + article.tags.join("、")}}</blockquote>
        <VueShowdown
          :markdown="article.content"
          flavor="vanilla"
          :options="{ emoji: true, tables: true }"
          :extensions="extensions"
        />
      </el-card>
    </el-col>
    <el-backtop></el-backtop>
  </el-row>
</template>

说明:

  • 上面的 CSS 文件也可以在 index.html 中直接引入,但是不建议这样用,因为容易出现在某个组件中直接刷新,CSS 文件加载不出来的情况
  • el-backtop 为Element-UI 提供的回顶部组件
  • 标题和文章信息暂时就用 h1 和 blockquote 来展示了,随后可能会进行美化

效果图:

文章详情页面

表格渲染:

表格渲染

参考代码:https://gitee.com/qianyucc/QBlog2/tree/v-5.0

Logo

前往低代码交流专区

更多推荐