• 【全栈】vue3.0 + golang 尝试前后端分离【博客系统1.0】开发


     1. 效果图

    背景:想在自己的vps上搭建一个个人博客系统,之前自己用宝塔+WordPress 搭建过一个不过 

     还是想自己用golang做个真正属于自己的博客系统,于是就有了标题所述....

    2. 贴下vue部分的代码,之前一直搞后端没有前端经验,发现vue对初学者还是很不错了

    整体代码结构:

    下面是组件部分:

    1. 导航:
    2. <template>
    3. <div class="app-bar">
    4. <div class="left-links">
    5. <router-link v-for="link in activeLinks" :key="link.name" :to="link.to" class="app-bar-item">
    6. {{ link.name }}
    7. </router-link>
    8. </div>
    9. <div class="right-links ">
    10. <router-link class="app-bar-item" href="#" v-if="!loggedIn" @click.prevent :to="{ name: 'Login' }">LOGIN</router-link>
    11. <a class="app-bar-item" href="#" v-if="loggedIn" @click.prevent="logoutButtonClicked">LOGOUT</a>
    12. </div>
    13. </div>
    14. </template>
    15. <script>
    16. import { mapActions, mapGetters } from "vuex";
    17. export default {
    18. data() {
    19. return {
    20. links: [
    21. {
    22. visibleIfLoggedOut: true,
    23. name: "Posts",
    24. to: {name: "Posts"}
    25. },
    26. {
    27. visibleIfLoggedOut: false,
    28. name: "User",
    29. to: {
    30. name: "User",
    31. params: {
    32. userid: this.$store.getters["auth/currentUser"].username
    33. }
    34. }
    35. }
    36. ]
    37. };
    38. },
    39. methods: {
    40. ...mapActions({
    41. login: "auth/login", // map `this.login()` to `this.$store.dispatch('auth/login')`
    42. logout: "auth/logout"
    43. }),
    44. logoutButtonClicked() {
    45. this.logout().then(() => {
    46. this.$router.push({name: "Login"});
    47. });
    48. }
    49. },
    50. computed: {
    51. ...mapGetters({loggedIn: "auth/isLoggedIn"}),
    52. activeLinks() {
    53. return this.links.filter(
    54. link => link.visibleIfLoggedOut || this.loggedIn
    55. );
    56. }
    57. }
    58. };
    59. </script>
    60. <style scoped>
    61. .app-bar {
    62. height: 5vh;
    63. width: 100%;
    64. position: fixed;
    65. z-index: 1;
    66. top: 0;
    67. left: 0;
    68. background-color: burlywood;
    69. overflow: hidden;
    70. display: block;
    71. justify-content: space-between;
    72. }
    73. .left-links {
    74. padding-left: 10%;
    75. }
    76. .left-links a {
    77. float: left;
    78. }
    79. a {
    80. float: left;
    81. display: block;
    82. color: #f2f2f2;
    83. text-align: center;
    84. padding: 14px 16px;
    85. text-decoration: none;
    86. font-size: 17px;
    87. }
    88. .right-links {
    89. float: right;
    90. }
    91. </style>

    添加文章或者评论:
     

    1. <template>
    2. <form>
    3. <label v-if="showLabel" :for="'text' + this._uid">{{ textRequest }}</label>
    4. <input
    5. :id="'text' + this._uid"
    6. type="text"
    7. :placeholder="textRequest"
    8. v-model="textValue"
    9. />
    10. <button @click.prevent="submitted">submit</button>
    11. </form>
    12. </template>
    13. <script>
    14. export default {
    15. data() {
    16. return {
    17. textValue: ""
    18. };
    19. },
    20. props: {
    21. textRequest: { type: String, default: "" },
    22. showLabel: { type: Boolean, default: false }
    23. },
    24. methods: {
    25. submitted() {
    26. this.$emit("text-added", this.textValue);
    27. this.textValue = "";
    28. }
    29. },
    30. emits: ["text-added"]
    31. };
    32. </script>
    33. <style scoped>
    34. label {
    35. padding-right: 1rem;
    36. display: block;
    37. }
    38. button {
    39. margin-top: 1rem;
    40. width: 10%;
    41. border-top-right-radius: 8px;
    42. border-bottom-right-radius: 8px;
    43. background-color: darksalmon;
    44. padding: 8px;
    45. }
    46. input {
    47. box-sizing: border-box;
    48. border-top-left-radius: 8px;
    49. border-bottom-left-radius: 8px;
    50. width: 80%;
    51. padding: 8px 20px;
    52. }
    53. input:focus {
    54. outline: 0;
    55. background-color: wheat;
    56. }
    57. </style>

     博文列表

    1. <template>
    2. <div>
    3. <h1>{{ title }}</h1>
    4. <div class="post-list" v-if="showPosts">
    5. <single-post v-for="post in posts" :key="post.id" :post="post">
    6. </single-post>
    7. </div>
    8. </div>
    9. </template>
    10. <script>
    11. import SinglePost from "@/components/SinglePost";
    12. export default {
    13. components: { SinglePost },
    14. props: ["posts", "title"],
    15. computed: {
    16. showPosts() {
    17. return this.posts && this.posts.length > 0;
    18. }
    19. }
    20. };
    21. </script>
    22. <style></style>

    单个帖子

    1. <template>
    2. <base-card :expandable="post.comments && post.comments.length > 0">
    3. <template v-slot:header>
    4. <h3>
    5. <router-link :to="linkUser(post.username)">{{postTitle(post) }}</router-link>
    6. </h3>
    7. <button class="delete-button" @click.prevent="deletePost">Delete</button>
    8. </template>
    9. <div class="text-wrapper">Say:{{post.post }}</div>
    10. <template v-slot:footer>
    11. <base-card v-for="comment in post.comments" :key="comment.id" :expandable="false">
    12. <template v-slot:header>
    13. <h3>
    14. <router-link :to="linkUser(comment.username)">{{postTitle(comment)}}</router-link>
    15. </h3>
    16. </template>
    17. {{ comment.post }}
    18. </base-card>
    19. </template>
    20. <template v-if="loggedIn" v-slot:actions>
    21. <add-text-form textRequest="Add comment" :showLabel="false" @text-added="text => addComment(text, post)"></add-text-form>
    22. </template>
    23. </base-card>
    24. </template>
    25. <script>
    26. import {mapGetters} from "vuex";
    27. import BaseCard from "@/components/UI/BaseCard";
    28. import AddTextForm from "@/components/AddTextForm";
    29. export default {
    30. components: { BaseCard, AddTextForm },
    31. props: ["post"],
    32. name: "SinglePost",
    33. computed: {
    34. ...mapGetters({
    35. loggedIn: "auth/isLoggedIn",
    36. currentUser: "auth/currentUser"
    37. })
    38. },
    39. methods: {
    40. postTitle(post) {
    41. return post.username + "@" + post.date;
    42. },
    43. linkUser(username) {
    44. return {
    45. name: "User",
    46. params: {
    47. userid: username
    48. }
    49. };
    50. },
    51. addComment(text, post) {
    52. this.$store.dispatch("posts/addComment", {
    53. postId: post.id,
    54. comment: {
    55. username: this.currentUser.userid,
    56. post: text
    57. }
    58. });
    59. },
    60. deletePost() {
    61. this.$store.dispatch("posts/deletePost", {post: this.post});
    62. }
    63. }
    64. };
    65. </script>
    66. <style>
    67. .text-wrapper {
    68. white-space: pre-wrap;
    69. }
    70. </style>

    ...

    后端代码:

    1. package endpoints
    2. import (
    3. "encoding/json"
    4. "github.com/gorilla/mux"
    5. "log"
    6. "net/http"
    7. )
    8. //AddRouterEndpoints add the actual endpoints for api
    9. func AddRouterEndpoints(r *mux.Router) *mux.Router {
    10. r.HandleFunc("/api/posts", getPosts).Methods("GET")
    11. r.HandleFunc("/api/posts", addPost).Methods("POST")
    12. r.HandleFunc("/api/posts/{POST_ID}", deletePost).Methods("DELETE")
    13. r.HandleFunc("/api/posts/{POST_ID}/comments", addComment).Methods("POST")
    14. return r
    15. }
    16. func sendJSONResponse(w http.ResponseWriter, data interface{}) {
    17. body, err := json.Marshal(data)
    18. if err != nil {
    19. log.Printf("Failed to encode a JSON response: %v", err)
    20. w.WriteHeader(http.StatusInternalServerError)
    21. return
    22. }
    23. w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    24. w.WriteHeader(http.StatusOK)
    25. _, err = w.Write(body)
    26. if err != nil {
    27. log.Printf("Failed to write the response body: %v", err)
    28. return
    29. }
    30. }

    ...

    3. 小结

    1. 整体感受,前后端分离,没有那么难;
    2. vue很多技术点还是比较模糊,用起来吭哧吭哧的,自己没有理解透,例如solts等;
    3. golang开发后端真的很快,相比运行部署完爆java;
    4. 目前只在单机上开发完成,未来要部署到自己的服务器上;
    5. 还没有接入DB存储,目前都是内存存储,不过用go介入存储mysql相信也很快;
    6. 没有设计,自己就是产品,还有很多需要学习的;
    7. 前期安装vue3.0可以参看官方手册;

    4. 源码

    完整的代码请留言...

  • 相关阅读:
    [附源码]java毕业设计高校新生报到管理系统
    性能测试-性能监控分析与调优(三)《实战》
    QT软件开发-基于FFMPEG设计视频播放器-支持软解与硬解(一)
    服务器系统和普通系统的区别
    java传base64返回给数据报404踩坑
    解决 IntelliJ IDEA 低版本与 Spring Boot 2.2+ 的测试兼容性问题
    基于Centos7.6安裝CDH6集群
    Spring 学习总结(35)—— Spring 6.0 新特性总结
    web网页设计期末课程大作业 HTML+CSS+JavaScript 美食餐饮文化主题网站设计 学生DW静态网页设计
    m基于matlab的无线光通信CDMA闭环链路功率控制算法仿真,对比了OOK,2PPM,4PPM,8PPM,16PPM
  • 原文地址:https://blog.csdn.net/qfzhangwei/article/details/126912668