In this project, we will build a fully functional blogging platform using Vue.js. This project will help you consolidate your knowledge of Vue.js by applying various concepts and techniques learned throughout the course. By the end of this module, you will have a comprehensive understanding of how to create a complex application with Vue.js.

Project Overview

Features

  • User Authentication (Login/Signup)
  • Create, Read, Update, and Delete (CRUD) operations for blog posts
  • Commenting system
  • Tagging system
  • User profiles
  • Responsive design

Technologies

  • Vue.js
  • Vue Router
  • Vuex
  • Axios (for HTTP requests)
  • Firebase (for backend services)

Step 1: Setting Up the Project

1.1 Initialize the Vue Project

First, create a new Vue project using Vue CLI.

vue create blogging-platform

Choose the default preset or customize it according to your needs.

1.2 Install Dependencies

Navigate to the project directory and install the necessary dependencies.

cd blogging-platform
npm install vue-router vuex axios firebase

1.3 Project Structure

Organize your project structure as follows:

blogging-platform/
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── router/
│   ├── store/
│   ├── views/
│   ├── App.vue
│   ├── main.js
├── .gitignore
├── package.json
├── README.md

Step 2: Setting Up Firebase

2.1 Create a Firebase Project

Go to the Firebase Console and create a new project.

2.2 Add Firebase to Your Project

In the Firebase console, add a web app to your project and copy the Firebase configuration.

2.3 Initialize Firebase in Your Vue Project

Create a firebase.js file in the src directory and initialize Firebase.

// src/firebase.js
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID"
};

firebase.initializeApp(firebaseConfig);

const db = firebase.firestore();
const auth = firebase.auth();

export { db, auth };

Step 3: Setting Up Vue Router

3.1 Create Router Configuration

Create a router.js file in the src/router directory.

// src/router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import Login from '../views/Login.vue';
import Signup from '../views/Signup.vue';
import BlogPost from '../views/BlogPost.vue';
import UserProfile from '../views/UserProfile.vue';

Vue.use(VueRouter);

const routes = [
  { path: '/', component: Home },
  { path: '/login', component: Login },
  { path: '/signup', component: Signup },
  { path: '/post/:id', component: BlogPost },
  { path: '/user/:id', component: UserProfile }
];

const router = new VueRouter({
  mode: 'history',
  routes
});

export default router;

3.2 Update main.js

Import and use the router in your main.js file.

// src/main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app');

Step 4: Setting Up Vuex

4.1 Create Vuex Store

Create a store.js file in the src/store directory.

// src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import { auth, db } from '../firebase';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    user: null,
    posts: []
  },
  mutations: {
    setUser(state, user) {
      state.user = user;
    },
    setPosts(state, posts) {
      state.posts = posts;
    }
  },
  actions: {
    async fetchPosts({ commit }) {
      const posts = [];
      const snapshot = await db.collection('posts').get();
      snapshot.forEach(doc => {
        posts.push({ id: doc.id, ...doc.data() });
      });
      commit('setPosts', posts);
    },
    async login({ commit }, { email, password }) {
      const userCredential = await auth.signInWithEmailAndPassword(email, password);
      commit('setUser', userCredential.user);
    },
    async signup({ commit }, { email, password }) {
      const userCredential = await auth.createUserWithEmailAndPassword(email, password);
      commit('setUser', userCredential.user);
    },
    async logout({ commit }) {
      await auth.signOut();
      commit('setUser', null);
    }
  },
  getters: {
    isAuthenticated(state) {
      return !!state.user;
    },
    getPosts(state) {
      return state.posts;
    }
  }
});

Step 5: Creating Components and Views

5.1 Create Authentication Components

Create Login.vue and Signup.vue in the src/views directory.

<!-- src/views/Login.vue -->
<template>
  <div>
    <h2>Login</h2>
    <form @submit.prevent="login">
      <input v-model="email" type="email" placeholder="Email" required />
      <input v-model="password" type="password" placeholder="Password" required />
      <button type="submit">Login</button>
    </form>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  data() {
    return {
      email: '',
      password: ''
    };
  },
  methods: {
    ...mapActions(['login']),
    async login() {
      try {
        await this.login({ email: this.email, password: this.password });
        this.$router.push('/');
      } catch (error) {
        console.error(error);
      }
    }
  }
};
</script>
<!-- src/views/Signup.vue -->
<template>
  <div>
    <h2>Signup</h2>
    <form @submit.prevent="signup">
      <input v-model="email" type="email" placeholder="Email" required />
      <input v-model="password" type="password" placeholder="Password" required />
      <button type="submit">Signup</button>
    </form>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  data() {
    return {
      email: '',
      password: ''
    };
  },
  methods: {
    ...mapActions(['signup']),
    async signup() {
      try {
        await this.signup({ email: this.email, password: this.password });
        this.$router.push('/');
      } catch (error) {
        console.error(error);
      }
    }
  }
};
</script>

5.2 Create Blog Post Component

Create BlogPost.vue in the src/views directory.

<!-- src/views/BlogPost.vue -->
<template>
  <div>
    <h2>{{ post.title }}</h2>
    <p>{{ post.content }}</p>
    <div>
      <h3>Comments</h3>
      <ul>
        <li v-for="comment in post.comments" :key="comment.id">{{ comment.text }}</li>
      </ul>
      <form @submit.prevent="addComment">
        <input v-model="newComment" placeholder="Add a comment" required />
        <button type="submit">Add Comment</button>
      </form>
    </div>
  </div>
</template>

<script>
import { db } from '../firebase';

export default {
  data() {
    return {
      post: {},
      newComment: ''
    };
  },
  async created() {
    const postId = this.$route.params.id;
    const doc = await db.collection('posts').doc(postId).get();
    this.post = { id: doc.id, ...doc.data() };
  },
  methods: {
    async addComment() {
      const postId = this.$route.params.id;
      const comment = { text: this.newComment };
      await db.collection('posts').doc(postId).update({
        comments: firebase.firestore.FieldValue.arrayUnion(comment)
      });
      this.post.comments.push(comment);
      this.newComment = '';
    }
  }
};
</script>

5.3 Create User Profile Component

Create UserProfile.vue in the src/views directory.

<!-- src/views/UserProfile.vue -->
<template>
  <div>
    <h2>{{ user.displayName }}</h2>
    <p>{{ user.email }}</p>
    <div>
      <h3>Your Posts</h3>
      <ul>
        <li v-for="post in userPosts" :key="post.id">{{ post.title }}</li>
      </ul>
    </div>
  </div>
</template>

<script>
import { db, auth } from '../firebase';

export default {
  data() {
    return {
      user: {},
      userPosts: []
    };
  },
  async created() {
    const userId = this.$route.params.id;
    const userDoc = await db.collection('users').doc(userId).get();
    this.user = { id: userDoc.id, ...userDoc.data() };

    const postsSnapshot = await db.collection('posts').where('authorId', '==', userId).get();
    postsSnapshot.forEach(doc => {
      this.userPosts.push({ id: doc.id, ...doc.data() });
    });
  }
};
</script>

Step 6: Final Touches

6.1 Add Navigation

Update App.vue to include navigation links.

<!-- src/App.vue -->
<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link>
      <router-link to="/login">Login</router-link>
      <router-link to="/signup">Signup</router-link>
    </nav>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
};
</script>

6.2 Styling

Add some basic styling to make the application look better.

/* src/assets/styles.css */
body {
  font-family: Arial, sans-serif;
}

nav {
  background-color: #333;
  padding: 1em;
}

nav a {
  color: white;
  margin: 0 1em;
  text-decoration: none;
}

nav a:hover {
  text-decoration: underline;
}

form {
  margin: 1em 0;
}

input {
  margin: 0.5em 0;
  padding: 0.5em;
  width: 100%;
}

button {
  padding: 0.5em 1em;
  background-color: #333;
  color: white;
  border: none;
  cursor: pointer;
}

button:hover {
  background-color: #555;
}

Import the styles in main.js.

// src/main.js
import './assets/styles.css';

Conclusion

Congratulations! You have successfully built a blogging platform using Vue.js. This project covered a wide range of topics, including user authentication, CRUD operations, and state management with Vuex. You also learned how to integrate Firebase for backend services and how to use Vue Router for navigation.

Summary

  • Set up a Vue.js project with Vue Router and Vuex.
  • Integrated Firebase for authentication and database services.
  • Created components and views for user authentication, blog posts, and user profiles.
  • Implemented CRUD operations and a commenting system.

Next Steps

  • Add more features such as likes, shares, and user avatars.
  • Improve the UI/UX with more advanced styling and animations.
  • Deploy your application to a hosting service like Firebase Hosting or Netlify.

By completing this project, you have gained valuable experience in building a real-world application with Vue.js. Keep practicing and exploring more advanced topics to further enhance your skills. Happy coding!

© Copyright 2024. All rights reserved