今天继续来写美食杰项目之个人空间,连载哦!!!
总体思路:
1.显示别人的空间
a.地址栏中如有userId 则显示对应的用户数据
2.显示自身空间
a.如果没有userId 则默认显示自己信息
b.如果在菜谱中 点击自己 也是有userId传递
c.通过判断是否为自己的 如果是,不需要后端拿,登录时,个人信息已经存在vuex中
个人空间页面效果展示:
代码展示:
space.vue:
<template>
<div class="space">
<h2>欢迎来到我的美食空间</h2>
<div class="user-info">
<div class="user-avatar">
<img :src="userInfo.avatar" alt="" />
</div>
<div class="user-main">
<h1>{{ userInfo.name }}</h1>
<span class="info">
<em>{{ userInfo.createdAt }}加入美食杰</em>
|
<router-link :to="{ name: 'edit' }" v-if="isOwner"
>编辑个人资料</router-link
>
</span>
<div class="tools" v-if="!isOwner">
<!-- follow-at no-follow-at-->
<a
href="javascript:;"
class="follow-at"
:class="{ 'no-follow-at': userInfo.isFollowing }"
@click="toggleHandler"
>
{{ userInfo.isFollowing ? "已关注" : "未关注" }}
</a>
</div>
</div>
<ul class="user-more-info">
<li>
<div>
<span>关注</span>
<strong>{{ userInfo.following_len }}</strong>
</div>
</li>
<li>
<div>
<span>粉丝</span>
<strong>{{ userInfo.follows_len }}</strong>
</div>
</li>
<li>
<div>
<span>收藏</span>
<strong>{{ userInfo.collections_len }}</strong>
</div>
</li>
<li>
<div>
<span>发布菜谱</span>
<strong>{{ userInfo.work_menus_len }}</strong>
</div>
</li>
</ul>
</div>
<!-- v-model="activeName" -->
<el-tabs class="user-nav" v-model="activeName" @tab-click="tabClickHandler">
<el-tab-pane label="作品" name="works"></el-tab-pane>
<el-tab-pane label="粉丝" name="fans"></el-tab-pane>
<el-tab-pane label="关注" name="following"></el-tab-pane>
<el-tab-pane label="收藏" name="collection"></el-tab-pane>
</el-tabs>
<div class="user-info-show">
<!-- 作品 & 收藏 布局 -->
<!-- <menu-card :margin-left="13"></menu-card> -->
<!-- 粉丝 & 关注 布局 -->
<!-- <Fans></Fans> -->
<router-view :info="list" :activeName="activeName"></router-view>
</div>
</div>
</template>
<script>
import {
userInfo,
toggleFollowing,
getMenus,
following,
fans,
collection,
} from "@/service/api";
const getOtherInfo = {
async works(params) {
//作品
// 先执行小括号里的
let data = (await getMenus(params)).data;
data.flag = "works";
return data;
},
async following(params) {
//关注
let data = (await following(params)).data;
data.flag = "following";
return data;
},
async fans(params) {
//粉丝
let data = (await fans(params)).data;
data.flag = "fans";
return data;
},
async collection(params) {
//收藏
let data = (await collection(params)).data;
data.flag = "collection";
return data;
},
};
export default {
name: "Space",
data() {
return {
userInfo: {},
isOwner: false,
activeName: "works",
list: [],
};
},
watch: {
// 监听路由变化,判断路由当中是否有信息,而分辨是否是自己的空间
$route: {
async handler() {
// 判断路由是否有信息
let { userId } = this.$route.query;
//
this.isOwner = !userId || userId === this.$store.state.userInfo.userId;
if (this.isOwner) {
//判断当前登录的用户
this.userInfo = this.$store.state.userInfo;
} else {
const { data } = await userInfo({ userId });
this.userInfo = data;
}
// console.log(this.userInfo)
// 可以留存上一次tab的访问信息(需求来定)
this.activeName = this.$route.name;
this.getInfo(); //请求二级路由数据
},
immediate: true,
},
},
methods: {
async toggleHandler() {
const { data } = await toggleFollowing({
followUserId: this.userInfo.userId,
});
// console.log(data)
// 关注后更新的表数据里还有粉丝所以整体赋值
this.userInfo = data;
},
tabClickHandler() {
//问题:在切换tab时,会发生key值重复的问题,在每次切换tab之前,先去清空数据
this.list = [];
//问题:给后端传递的参数被覆盖(query)
this.$router.push({
name: this.activeName,
query: {
...this.$route.query,
},
});
},
//调用封装
async getInfo() {
let data = await getOtherInfo[this.activeName]({
userId: this.userInfo.userId,
});
//给组件赋值
// console.log(data)
if (this.activeName === data.flag) {
this.list = data.list;
}
},
},
};
</script>
<style lang="stylus">
.space
h2
text-align center
margin 20px 0
.user-info
height 210px
background-color #fff
display flex
.user-avatar
width 210px
height 210px
img
width 100%
height 100%
.user-main
width 570px
padding 20px
position relative
h1
font-size 24px
color #333
line-height 44px
.info
font-size 12px
line-height 22px
color #999
a
color #999
.tools
position absolute
right 20px
top 20px
vertical-align top;
a
display inline-block
padding 3px 0
width 50px
color #fff
text-align center
a.follow-at
background-color #ff3232
a.no-follow-at
background-color #999
.user-more-info
width 190px
overflow hidden
padding-top 20px
li
width 81px
height 81px
border-radius 32px
border-bottom-right-radius 0
margin 0px 8px 8px 0px
float left
div
display block
height 81px
width 81px
box-shadow 0px 0px 6px rgba(0,0,0,0.05) inset
border-radius 32px
border-bottom-right-radius 0
span
color #999
line-height 20px
display block
padding-left 14px
padding-top 14px
strong
display block
font-size 18px
color #ff3232
font-family Microsoft Yahei
padding-left 14px
line-height 32px
.user-nav
margin 20px 0 20px 0
.user-info-show
min-height 300px
background #fff
padding-top 20px
.info-empty
width 100%
min-height inherit
display flex
align-items center
justify-content:center;
p
text-align center
font-size 12px
a
text-align center
display block
height 48px
width 200px
line-height 48px
font-size 14px
background #ff3232
color #fff
font-weight bold
margin 0px auto
.el-tabs__item.is-active
color: #ff3232;
.el-tabs__active-bar
background-color: #ff3232;
.el-tabs__nav-wrap::after
background-color: transparent;
</style>
这个页面是用tab切换来写的,点击作品,粉丝,关注,收藏,分别会跳转到各自页面,下面展示代码:
<template>
<div class="fans">
<div class="info-empty" v-if="!info.length">
<div>
<p v-if="activeName === 'fans'">
还没有被关注哦!多发布菜谱,更容易被找到。
</p>
<p v-if="activeName === 'following'">
还没有关注别人哦!可以预览菜谱,找到别人
</p>
</div>
</div>
<ul class="fans clearfix">
<router-link
v-for="item in info"
:key="item.userId"
:to="{ name: 'space', query: { userId: item.userId } }"
tag="li"
>
<a href="javascript:;" class="img"> <img :src="item.avatar"/></a>
<div class="c">
<strong class="name">
<router-link
:to="{ name: 'space', query: { userId: item.userId } }"
>{{ item.name }}</router-link
>
</strong>
<em class="info">
<span>粉丝:</span>{{ item.follows_len }} | <span>关注:</span
>{{ item.following_len }}
</em>
<em class="info" v-if="item.sign">
<span>简介:{{ item.sign }}</span>
这个人太懒啦!还没有介绍自己
</em>
</div>
</router-link>
</ul>
</div>
</template>
<script>
export default {
props: {
info: {
type: Array,
default: () => [],
},
activeName: {
type: String,
default: "fans",
},
},
};
</script>
<style lang="stylus">
.fans
font-size 12px
.fans li
height 80px
width 950px
border-bottom 1px solid #eee
padding 20px 20px
position relative
.fans lihover
background #fafafa
.fans li a.img
float left
height 80px
width 80px
position relative
.fans li a.img img
height 80px
width 80px
display block
.fans li div.c
float left
height 80px
width 850px
padding-left 14px
.fans li div.c strong.name
display block
height 32px
line-height 32px
font-size 14px
color #333
font-weight bold
.fans li div.c strong.name a
color #333
.fans li div.c strong.name a span
color #ff3232
.fans li div.c strong.name ahover
color #ff3232
text-decoration underline
.fans li div.c p
font-size 14px
color #666
line-height 24px
height 48px
overflow hidden
.fans li div.c p a
color #666
.fans li div.c p ahover
color #ff3232
text-decoration underline
.fans li div.c p strong
font-size 12px
padding-right 10px
.fans li div.c p strong em
color #ff3232
padding-right 4px
.fans li div.c span.time
position absolute
height 20px
line-height 20px
right 20px
top 20px
color #999
.fans li div.c span.time a
color #999
padding-left 10px
display none
.fans li div.c span.time ahover
color #ff3232
.fans li div.c em.info
height 24px
line-height 24px
display block
color #999
.fans li div.c em.info span
color #666
</style>
点击跳转是需要配置路由的:
router下的index.js页面:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import {userInfo}from '@/service/api.js'
import Home from '@/views/home/Home.vue'
import Store from '@/store'
const Recipe=()=>import('@/views/recipe/recipe');
const Create=()=>import('@/views/create/create');
const Edit=()=>import('@/views/user-space/edit');
const Menulist=()=>import('@/views/user-space/menu-list');
const Fans=()=>import('@/views/user-space/fans');
const Space=()=>import('@/views/user-space/space');
const Detail=()=>import('@/views/detail/detail');
const Login=()=>import('@/views/user-login/index');
const router = new Router({
mode:"history",
routes:[
{
path:'/',
name:"Home",
title:"首页",
component:Home
},
{
path:'/login',
name:"login",
title:"登录页",
component:Login,
meta:{
login: true
},
},
{
path:'/edit',
name:"edit",
title:"编辑个人资料",
component:Edit,
meta:{
login: true
},
},
{
path:'/menulist',
name:"menulist",
title:"菜谱编辑",
component:Menulist,
meta:{
login: true
},
},
{
path:'/create',
name:"create",
title:"发布菜谱",
component:Create,
meta:{
login: true
},
},
{
path:'/recipe',
name:"recipe",
title:"发布菜谱",
component:Recipe,
meta:{
login: true
},
},
{
path:'/detail',
name:"detail",
title:"菜谱编辑",
component:Detail,
meta:{
login: true
},
},
{
path:'/space',
name:"space",
title:"个人空间",
component:Space,
meta:{
login: true
},
children:[
{
path:'/works',
name:"works",
title:"作品",
component:Menulist,
meta:{
login: true
},
},
{
path:'/fans',
name:"fans",
title:"我的粉丝",
component:Fans,
meta:{
login: true
},
},
{
path:'/following',
name:"following",
title:"我的关注",
component:Fans,
meta:{
login: true
},
},
{
path:'/collection',
name:"collection",
title:"收藏",
component:Menulist,
meta:{
login: true
},
},
]
},
// ...viewsRoute,
{
path:"*",
name:"noFound",
title:"未找到",
redirect:{
name:"Home"
}
},
]
});
//路由守卫
router.beforeEach(async (to,from,next)=>{
const token=localStorage.getItem('token');//获取login里的数据
const isLogin=!!token;//两个感叹号转布尔值
//进入路由的时候,向后端发送token,验证是否合法
const data =await userInfo();
Store.commit('chageUserInfo',data.data);
//判断是否需要登录:如果meta中的为true那么需要登录
if (to.matched.some(item=>item.meta.login)) {//需要登录
console.log("需要登录")
if (isLogin) {//已经登录但已经登陆就直接通过
if (data.error === 400) {
next({name:'login'});
localStorage.removeItem('token');//移除本地存储
return;
}
if (to.name=== 'login') {
next({name:'home'})
}else{
next();
}
next();
return;
}
if(!isLogin && to.name==='login') {//没有登陆,仍需要去登录页
next();
}
if(!isLogin && to.name !=='login') {//没有登陆,去的也不是登录页
next({name:"login"});
}
} else{
next();
}
})
export default router;
以上就是美食杰项目个人空间页面,谢谢观看,有不懂的地方欢迎提问!!!