项目实战:博客项目

一、项目介绍

 

 

此项目为博客项目,涉及的技术栈有vue、vuex、路由、ajax、bootstrap的使用

实现了关注用户、发帖、删帖、登录、注册的功能

二、项目收获

通过项目练习,对技术有了更加深刻的了解

三、设计思路

通过vue ui对项目进行初始化配置

安装依赖

 

  设置六个页面,

通过路由,在app.vue中进行挂载

import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LoginView from "../views/LoginView"
import NotFoundView from "../views/NotFoundView"
import RegisterView from "../views/RegisterView"
import UserList from "../views/UserList"
import UserProfile from "../views/UserProfile"
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/LoginView',
    name: 'LoginView',
    component: LoginView
  },
  {
    path: '/NotFoundView',
    name: 'NotFoundView',
    component: NotFoundView
  },
  {
    path: '/RegisterView',
    name: 'RegisterView',
    component: RegisterView
  },
  {
    path: '/UserList',
    name: 'UserList',
    component: UserList
  },
  {
    path: '/UserProfile/:userId',
    name: 'UserProfile',
    component: UserProfile
  },
  {
    path:"/404",
    component:NotFoundView
  },{
    path:"/:catchAll(.*)",
    redirect: "/404"
  }


]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router

设置导航栏组件,进行路由切换

在路由组件中,userprofile需要传入参数,因为不同的用户所打开的主页,展示的效果可能不同,如果登录id等于打开的主页id,那么就可以展示发帖和删帖的组件;

注意引入对象,在实例化的时候,有的需要加括号,比如store()

<template>
  <nav class="navbar navbar-expand-lg bg-body-tertiary p-3 mb-2 bg-light text-dark ">
  <div class="container">
    <a class="navbar-brand" href="#">Myspace</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <router-link class="nav-link active" aria-current="page" :to="{name:`home`}">首页</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{name:`UserList`}">好友列表</router-link>
        </li>
       
      </ul>




      
    <ul class="navbar-nav" v-if="!$store.state.user.is_login">
      <li class="nav-item">
          <router-link class="nav-link" :to="{name:`LoginView`}">登录</router-link>
        </li>
        <li class="nav-item">
          <router-link class="nav-link" :to="{name:`RegisterView`}">注册</router-link>
        </li>
    </ul>
    <ul class="navbar-nav" v-else>
      <li class="nav-item">
          <router-link class="nav-link" :to="{name:`UserProfile`,params:{userId:$store.state.user.id}}">{{$store.state.user.username}}</router-link>
        </li>
        <li class="nav-item">
<a  class="nav-link" style="cursor: pointer;" @click="logout"> 退出</a>
        </li>
    </ul>
    </div>
  </div>
</nav>
</template>

<script>
import { useStore } from 'vuex';
export default {
setup(){
  const store=useStore();
  const logout=()=>{
    store.commit("logout")
  }


  return {
    logout
  }
}
}
</script>

<style>

</style>

首先对用户列表进行实现

<template>
    <div>
     <ContentBase>
       <div class="card" v-for="use in user" :key="use.id" @click="open_profile(use.id)">
        <div class="card-body">
            <div class="row">
                <div class="col-1">
                    <img :src="use.photo" alt="" class="img-fluid">
                </div>
                <div class="col-11">
                  <div class="username">{{ use.username }}</div>
                  <div class="follower">{{ use.followerCount }}</div>
                </div>
            </div>
        </div>
       </div>
     </ContentBase>
    
    </div>
  </template>
  
  <script>
  import { useStore } from 'vuex';

  import ContentBase from '@/components/ContentBase.vue';
  import $ from "jquery";
  import {ref} from "vue";
  import router from '@/router';
  export default {
  components:{
    ContentBase
  },
  setup(){
    const store=useStore();//忘记加括号
   
    let user=ref([]);
    $.ajax({
        url:"https://app165.acapp.acwing.com.cn/myspace/userlist/",
        type:"get",
        success(resp){
            user.value=resp;
        }
    })

    const open_profile=userId=>{
        if(store.state.user.is_login)
        {router.push({
            name:"UserProfile",
            params:{
                userId
            }
        })}
        else {
            router.push({name:"LoginView"})
        }
    }

    return {
        user,open_profile
    }
  }
  }
  </script>
  
  <style scoped>
  img{
    border-radius: 50%;
  }
  .username{
    font-weight: bold;
    height: 50%;
  }
  .follower{
    font-size: 12px;
    color: goldenrod;
    height:50%
  }
  .card{
    margin-top: 20px;
    cursor: pointer;
  }
  .card:hover{
    box-shadow:2px 2px 10px rgb(5, 28, 91) ;
    transition: 0.5s;
  }
  </style>

再对个人主页进行实现

<template>
    <div>
     <ContentBase>
        <div class="row">
            <div class="col-3">
                <UserProfileInfo :user="user" @followme="follow" ></UserProfileInfo>
                <UserProfileWrite v-if="is_me" class="write" @sendme="sendit"></UserProfileWrite>
            </div>
                <div class="col-9">
                    <UserProfilePosts :postme="posts" :user="user"  @del="delone"></UserProfilePosts>
                </div>
            
        </div>
     </ContentBase>
    
    </div>
  </template>
  
  <script>
  import ContentBase from '@/components/ContentBase.vue';
  import UserProfileInfo from '@/components/UserProfileInfo.vue';
  import UserProfilePosts from "@/components/UserProfilePosts.vue";
  import UserProfileWrite from '@/components/UserProfileWrite.vue';
  import $ from "jquery"
  import {computed, reactive}from "vue"
  import { useStore } from 'vuex';
  import { useRoute } from 'vue-router';

  export default {
  components:{
    ContentBase,
    UserProfileInfo,
    UserProfilePosts,
     UserProfileWrite
  },
  setup(){
    const store=useStore();
    const route=useRoute();
  const user=reactive({});
  const posts=reactive({});
    const userId=route.params.userId

  $.ajax({
    url:"https://app165.acapp.acwing.com.cn/myspace/getinfo/",
    type:"get",
    data:{
        user_id:userId
    },
    headers:{
        "Authorization":"Bearer "+store.state.user.access
    },
    success(resp){
        user.id=resp.id;
        user.username=resp.username;
        user.photo=resp.photo;
        user.is_followed=resp.is_followed;
        user.followerCount=resp.followerCount
    }

  })

  $.ajax({
    url:"https://app165.acapp.acwing.com.cn/myspace/post/",
    type:"get",
    data:{
        user_id:userId
    },
    headers:{
        "Authorization":"Bearer "+store.state.user.access
    },
    success(resp){
        posts.posts=resp;
     
    },
    error(){
        console.log("failed")
    }
  })

   const sendit=(content)=>{
    posts.count++;
    posts.posts.unshift({
        id:posts.count,
        content:content
    });
    $.ajax({
        url:"https://app165.acapp.acwing.com.cn/myspace/post/",
        type:"post",
        data:{content:content},
        headers:{
        "Authorization":"Bearer "+store.state.user.access
    },
    })
   }



   const follow= ()=>{ 
    if(user.is_followed)user.followerCount--;
    else user.followerCount++;
    user. is_followed=!user.is_followed;
   
   }


   const delone=(id)=>{
    $.ajax({
        url:"https://app165.acapp.acwing.com.cn/myspace/post/",
        type:"delete",
        data:{
            post_id:id
        },
        headers:{
        "Authorization":"Bearer "+store.state.user.access
    },
   
    success(){console.log("go")}
    }),
     posts.posts=posts.posts.filter(post=>post.id!=id);
     posts.count=posts.posts.length//为什么前端必须删除:因为告诉服务器之后,自己并不会立即刷新删除
   }

   const is_me=computed(()=>userId==store.state.user.id)

   return {user,follow,posts,sendit,is_me,delone}//必须要双引号
  }
  }
  </script>
  
  <style>
  .write{
    margin-top: 20px;
  }
  </style>

接着实现登录功能

<template>
    <div> <ContentBase>
        <div class="row justify-content-md-center">
            <div class="col-3">
            <form @submit.prevent="login">              
            <div class="mb-3">
                <label for="username" class="form-label">用户名</label>
                <input v-model="username" type="text" class="form-control" id="username" >
            
            </div>
            <div class="mb-3">
                <label for="password" class="form-label">密码</label>
                <input v-model="password" type="password" class="form-control" id="password">
            </div>
            
            <button type="submit" class="btn btn-primary">登录</button>
            </form>
            </div>
        </div>
    
        
     </ContentBase>
    
    </div>
  </template>
  
  <script>
  import {useStore} from "vuex"//store的s要大写
  import {ref} from "vue"
  import ContentBase from '@/components/ContentBase.vue';
  import router from "@/router/index"
  export default {
  components:{
    ContentBase
  },
  setup(){
    const store=useStore();
    let password=ref("")
    let username=ref("")
    const login=()=>{
        store.dispatch('login', {
            username:username.value, 
            password:password.value,
            success(){
                router.push({name:`UserList`})
            }
        })
    }
    

    return {
        password,username,login
    }
  }
  }
  </script>
  
  <style scoped>
  button{
    width: 100%;
  }
  
  </style>

登录时输入的信息需要存到vuex中


import $ from "jquery"
import jwt_decode from "jwt-decode";
const moudleUser={
state:{
    id:"",
    username:"",
    photo:"",
    followercount:0,
    access:"",
    refresh:"",
    is_login:false
},
getters:{

},
mutations: {
    updateUser(state,user){
        state.id=user.id;
        state.username=user.username;
        state.photo=user.photo;
        state.followercount=user.followercount;
        state.access=user.access;
        state.refresh=user.refresh;
        state.is_login=user.is_login
    },
    updateAccess(state,access){
        state.access=access
    },
    logout(state){
        state.id="";
        state.username="";
        state.photo="";
        state.followercount=0;
        state.access="";
        state.refresh="";
        state.is_login=false
    }
},
actions: {
    login(context,data){
        $.ajax({
            url:"https://app165.acapp.acwing.com.cn/api/token/",
            type:"post",
            data:{
                username:data.username,
                password:data.password
            },
            success(resp){
                const {access,refresh}=resp;
                const access_obj=jwt_decode(access)

                setInterval(() => {
                    $.ajax({
                        url:"https://app165.acapp.acwing.com.cn/api/token/refresh/",
                        type:"post",
                        data:{
                            refresh
                        },
                        success(resp){
                           context.commit("updateAccess",resp.access) 
                        }
                    })
                }, 4.5*60*1000);


                $.ajax({
                    url:"https://app165.acapp.acwing.com.cn/myspace/getinfo/",
                    type:"get",
                    data:{
                        user_id:access_obj.user_id
                    },
                    headers:{
                        "Authorization":"Bearer " +access//bearer需要加空格
                    },
                    success(resp){
                        context.commit("updateUser",{
                            ...resp,
                            access:access,
                            refresh:refresh,
                            is_login:true
                        })

                        data.success();
                    }
                })
            }
        })
    }
}
}

export default moudleUser

然后实现注册功能

<template>
    <div> <ContentBase>
        <div class="row justify-content-md-center">
            <div class="col-3">
            <form @submit.prevent="register">              
            <div class="mb-3">
                <label for="username" class="form-label">用户名</label>
                <input v-model="username" type="text" class="form-control" id="username" >
            
            </div>
            <div class="mb-3">
                <label for="password" class="form-label">密码</label>
                <input v-model="password" type="password" class="form-control" id="password">
            </div>
            <div class="mb-3">
                <label for="password" class="form-label">确认密码</label>
                <input v-model="confirm" type="password" class="form-control" id="password">
            </div>
            <span>{{ tt}}</span>
            <button type="submit" class="btn btn-primary">登录</button>
            </form>
            </div>
        </div>
    
        
     </ContentBase>
    
    </div>
  </template>
  
  <script>

  import {ref} from "vue"
  import { useStore } from "vuex";
  import router from "@/router"//不是useroute
  import $ from "jquery"
  import ContentBase from '@/components/ContentBase.vue';

  export default {
  components:{
    ContentBase
  },
  setup(){
   
    let password=ref("")
    let username=ref("")
    let confirm=ref("")
    let tt=ref("")
    const store =useStore();
    const register=()=>{
       $.ajax({
        url:"https://app165.acapp.acwing.com.cn/myspace/user/",
        type:"post",
        data:{
            username:username.value,
            password:password.value,
            password_confirm:confirm.value
        },
        success(resp){
            tt.value    =resp.result,
            console.log(resp)
            store.dispatch("login",{
                username:username.value,
                password:password.value,//注意ref需要value
                success(){
                router.push({name:"UserList"})
            }

            });
           


        },
        error(resp){
            tt=resp
        }
       })
    }
    

    return {
        password,username,confirm,register,tt
    }
  }
  }
  </script>
  
  <style scoped>
  button{
    width: 100%;
  }
  
  </style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值