返回

Vue 实战加油,加油 fighting!

前端

实战篇 - 从零构建 CNode 社区之组件篇

CNode 社区是一个开源的社区论坛,使用 Vue.js 构建。在本文中,我们将从零开始构建一个 CNode 社区,并介绍如何使用 Vue.js 构建组件。

组件

组件是 Vue.js 中的一种重要概念。组件可以被看作是一个独立的、可重用的代码块,它可以被多次使用。这使得 Vue.js 非常适合构建大型、复杂的应用程序。

在 CNode 社区中,我们将使用组件来构建以下内容:

  • Header:头部
  • Posltlist:首页列表
  • Article:文章的详情页
  • Sidebar:侧边栏
  • Userinfo:用户个人信息
  • 分页

Header

Header 是 CNode 社区的主页顶部。它包括以下元素:

  • 网站名称
  • 导航栏
  • 搜索框
<template>
  <header>
    <div class="container">
      <div class="logo">
        <h1>CNode</h1>
      </div>
      <nav>
        <ul>
          <li><a href="/">首页</a></li>
          <li><a href="/topics">话题</a></li>
          <li><a href="/users">用户</a></li>
        </ul>
      </nav>
      <div class="search">
        <input type="text" placeholder="搜索">
        <button type="submit">搜索</button>
      </div>
    </div>
  </header>
</template>

<script>
export default {
  name: 'Header'
}
</script>

<style>
header {
  background-color: #f5f5f5;
  padding: 20px 0;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
}

.logo {
  float: left;
  font-size: 24px;
  font-weight: bold;
}

nav {
  float: right;
}

nav ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

nav li {
  display: inline-block;
  margin-right: 20px;
}

nav a {
  text-decoration: none;
  color: #333;
}

nav a:hover {
  color: #000;
}

.search {
  float: right;
  margin-left: 20px;
}

.search input {
  width: 200px;
  height: 30px;
  padding: 0 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

.search button {
  width: 80px;
  height: 30px;
  padding: 0 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background-color: #333;
  color: #fff;
}

.search button:hover {
  background-color: #000;
}
</style>

Posltlist

Posltlist 是 CNode 社区的首页列表。它包括以下元素:

  • 文章列表
  • 分页
<template>
  <div class="posltlist">
    <div class="container">
      <ul class="list">
        <li v-for="post in posts" :key="post.id">
          <div class="title">
            <a :href="'/post/' + post.id">{{ post.title }}</a>
          </div>
          <div class="info">
            <span>{{ post.author.username }}</span>
            <span>{{ post.create_at }}</span>
          </div>
        </li>
      </ul>
      <div class="pagination">
        <ul>
          <li v-for="page in pages" :key="page">
            <a :href="'/page/' + page">{{ page }}</a>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Posltlist',
  data() {
    return {
      posts: [],
      pages: []
    }
  },
  created() {
    this.getPosts()
  },
  methods: {
    getPosts() {
      // 从服务器获取文章列表
      axios.get('/api/posts')
        .then(response => {
          this.posts = response.data.data
        })
        .catch(error => {
          console.log(error)
        })
    }
  }
}
</script>

<style>
.posltlist {
  padding: 20px 0;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
}

.list {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

.list li {
  border-bottom: 1px solid #ccc;
  padding: 10px 0;
}

.list li:last-child {
  border-bottom: none;
}

.title {
  font-size: 18px;
  font-weight: bold;
}

.title a {
  text-decoration: none;
  color: #333;
}

.title a:hover {
  color: #000;
}

.info {
  color: #999;
  font-size: 12px;
}

.pagination {
  margin-top: 20px;
}

.pagination ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

.pagination li {
  display: inline-block;
  margin-right: 10px;
}

.pagination a {
  text-decoration: none;
  color: #333;
}

.pagination a:hover {
  color: #000;
}
</style>

Article

Article 是 CNode 社区的文章详情页。它包括以下元素:

  • 文章标题
  • 文章内容
  • 评论列表
  • 评论框
<template>
  <div class="article">
    <div class="container">
      <div class="title">
        <h1>{{ post.title }}</h1>
      </div>
      <div class="content">
        <div v-html="post.content"></div>
      </div>
      <div class="comments">
        <ul>
          <li v-for="comment in comments" :key="comment.id">
            <div class="author">
              {{ comment.author.username }}
            </div>
            <div class="content">
              <div v-html="comment.content"></div>
            </div>
          </li>
        </ul>
      </div>
      <div class="comment-box">
        <form @submit.prevent="submitComment">
          <div class="form-group">
            <textarea v-model="newComment.content" placeholder="发表评论"></textarea>
          </div>
          <div class="form-group">
            <button type="submit">发表评论</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Article',
  data() {
    return {
      post: {},
      comments: [],
      newComment: {
        content: ''
      }
    }
  },
  created() {
    this.getPost()
    this.getComments()
  },
  methods: {
    getPost() {
      // 从服务器获取文章详情
      axios.get('/api/post/' + this.$route.params.id)
        .then(response => {
          this.post = response.data.data
        })
        .catch(error => {
          console.log(error)
        })
    },
    get