博客前台搭建

77 阅读1分钟

博客前台

博客列表

列表项组件

补充列表项组件: frontend/BlogItem.vue

<template>
  <div>
    <h2 class="title">
      {{ title }}
    </h2>
    <div class="describe">
      <div>发表于: {{ publishAt }}</div>
      <a-divider direction="vertical" />
      <div>作者: {{ author }}</div>
    </div>
    <div class="summary">
      {{ summary }}
    </div>
    <div class="more">
      <a-button size="mini" type="dashed">阅读全文 »</a-button>
    </div>
  </div>
</template>

<script setup>
defineProps({
  title: String,
  publishAt: Number,
  author: String,
  summary: String,
});
</script>

<style lang="less" scoped>
.title {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  color: #555;
}

.describe {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  color: #999;
  font-size: 12px;
}

.summary {
  color: #333;
  font-size: 14px;
  line-height: 1.6;
  margin: 10px 0 10px 0;
}

.more {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
}
</style>

列表页

博客列表页: frontend/BlogView.vue

<script setup>
import BlogItem from "./BlogItem.vue";
</script>

<template>
  <div class="content">
    <a-space direction="vertical" style="width: 700px">
      <BlogItem
        title="测试"
        publishAt="1662978665"
        author="测试"
        summary="Java启动命令是所有java应用程序的入口,通过它来启动Java运行时环境,并加载相关的class。不过由于IDE的盛行,我们Java程序员中的大多数并不是非常的了解Java启动命令。本文希望做一个Java启动命令的汇总,和各位同道分享,也便于日后作为自己的参考"
      ></BlogItem>
      <BlogItem
        title="测试"
        publishAt="1662978665"
        author="测试"
        summary="测试"
      ></BlogItem>
      <BlogItem
        title="测试"
        publishAt="1662978665"
        author="测试"
        summary="测试"
      ></BlogItem>
    </a-space>
  </div>
</template>

<style lang="less" scoped>

.content {
  width: 100%;
}
</style>

博客详情页

由于博客是 Markdown 的, 所以我们需要选择一个支持 Markdown 编辑与展示的 Vue3 的库: 这里选择使用md-editor-v3

md-editor-v3库介绍

安装md-editor-v3:

npm i md-editor-v3

使用方法:

<template>
  <md-editor v-model="text" preview-only />
</template>

<script setup>
import { ref } from 'vue';
import MdEditor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';

const text = ref('# Hello Editor');
</script>

详情页组件

frontend/BlogDetail.vue

<template>
  <div>
    <h2 class="title">
      {{ title }}
    </h2>
    <div class="describe">
      <div>发表于: {{ publishAt }}</div>
      <a-divider direction="vertical" />
      <div>作者: {{ author }}</div>
    </div>
    <div style="width: 700px">
      <md-editor
        v-model="text"
        preview-only
        style="height: calc(100vh - 85px)"
      />
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";
import MdEditor from "md-editor-v3";
import "md-editor-v3/lib/style.css";

const title = "测试";
const publishAt = 10000;
const author = "测试";
const text = ref(`## 参考

+ [博客样式参考](http://www.arccode.net/)
+ [md-editor-v3 官方页面](https://imzbf.github.io/md-editor-v3/index)
+ [md-editor-v3 Github](https://github.com/imzbf/md-editor-v3)`);
</script>

<style lang="less" scoped>
.title {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  color: #555;
}

.describe {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  color: #999;
  font-size: 12px;
}
</style>

index.js 中添加子路由

{
      path: "/frontend",
      name: "frontend",
      component: FrontendLayout,
      children: [
        {
          path: "blogs",
          name: "BlogView",
          component: () => import("@/views/frontend/BlogView.vue"),
        },
        {
          path: "blogs/:id",
          name: "BlogDetail",
          component: () => import("@/views/frontend/BlogDetail.vue"),
        },
      ],
    },

image.png

列表页跳转

frontend/BlogItem.vue

阅读全文补充跳转:

<a-button size="mini" type="dashed" @click="jumpToDetail"
>阅读全文 »</a-button>

跳转到详情页

const router = useRouter();
const jumpToDetail = () => {
  router.push({ path: `blogs/xxx` });
};

对接后端

src 目录里新建 api 目录 进行对后端的对接 新建 client.js

import axios from "axios";

const client = axios.create({
  timeout: 5000,
});

// 添加请求拦截器,用于认证, 都需要携带 Token,或者 basic AUTH
client.interceptors.request.use(
  (request) => {
    return request;
  },
  (error) => {
    console.log(error);
  }
);
// 添加响应拦截器, 用于处理返回异常, code != 0
client.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    console.log(error);
  }
);

export default client;

我们在 api文件夹内 新建 blog.js 存储对博客页面的操作

对接列表页

//blog.js
import client from "./client.js";

export function LIST_BLOG(params) {
  return client({
    url: "/vblog/api/v1/blog/",
    method: "get",
    params: params,
  });
}

BlogView.vue 进行修改,使他从后端获取数据并显示

<script setup>
import BlogItem from "./BlogItem.vue";
import { LIST_BLOG } from "@/api/blog.js";
import { onMounted, ref } from "vue";

const blogs = ref([]);
onMounted(async () => {
  try {
    const resp = await LIST_BLOG();
    blogs.value = resp.data.items;
  } catch (error) {
    console.log(error);
  }
});
console.log(blogs);
</script>

<template>
  <div class="content">
    <a-space direction="vertical" style="width: 700px">
      <div v-for="item in blogs" :key="item.id">
        <BlogItem
          v-if="item.status === 'published'"
          :id="item.id"
          :title="item.title_name"
          :publishAt="item.publish_at"
          :author="item.author"
          :summary="item.summary"
        ></BlogItem>
      </div>
    </a-space>
  </div>
</template>

<style lang="less" scoped>
.content {
  width: 100%;
}
</style>

自己试试吧

image.png

image.png

对接详情页

blog.js 添加 GET_BLOG 方法

export function GET_BLOG(id, params) {
  return client({
    url: `/vblog/api/v1/blog/${id}`,
    method: "get",
    params: params,
  });
}

修改 BlogItem.vue 的 script 部分

  • Props 里新增 id 字段接收 URL 的id
  • router.push 通过路由名称和 params 的 id 组合
import { useRouter } from "vue-router";

const pros = defineProps({
  id: Number,
  title: String,
  publishAt: Number,
  author: String,
  summary: String,
});

const router = useRouter();
const JumpToDetail = () => {
  router.push({ name: "BlogDetail", params: { id: pros.id } });
};

大幅度修改 BlogDetail.vue

<template>
  <div>
    <h2 class="title">
      {{ data.title_name }}
    </h2>
    <div class="describe">
      <div>发表于: {{ data.publish_at }}</div>
      <a-divider direction="vertical" />
      <div>作者: {{ data.author }}</div>
    </div>
    <div class="summary">
      {{ data.summary }}
    </div>
    <div style="width: 700px">
      <md-editor v-model="data.content" preview-only />
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import MdEditor from "md-editor-v3";
import "md-editor-v3/lib/style.css";
import { GET_BLOG } from "@/api/blog.js";
import { useRoute } from "vue-router";

const data = ref({});

onMounted(async () => {
  try {
    // id 从路由里面获取, 读取的路由对象
    const route = useRoute();
    console.log(route.params.id);
    const resp = await GET_BLOG(route.params.id);
    console.log(resp);
    data.value = resp.data;
  } catch (error) {
    console.log(error);
  }
});
</script>

<style scoped>
.title {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  color: #555;
}

.describe {
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  color: #999;
  font-size: 12px;
}

.summary {
  margin: 8px;
  color: #555;
}
</style>

试试吧!

image.png