目录
- 一、效果图
- 二、项目结构
- 三、界面效果和代码实现
-
- 1.路由注册
- 2.个人主页实现
- 3.编辑弹窗按钮实现
- 4.个人简介实现
- 5.发贴页实现
- 6.收藏页实现
- 7.关注和收藏页实现
- 四、总结
一、效果图
仿照原神社区的个人中心写了个个人中心界面,下图分别为原神社区个人中心主页和我画的个人中心的效果图:
原神社区个人中心效果图:
我画的个人中心效果图:
下面上代码
二、项目结构
router文件夹里的index.js为路由注册文件,person文件夹里Info文件为个人简介页,MyArticle文件为发布页,MyCollect为文件收藏页,MyFanAndFollow文件为粉丝和关注页,Personal文件为个人中心主页,PersonalDia文件为编辑按钮弹窗。
三、界面效果和代码实现
1.路由注册
首先要去router文件夹的index.js文件进行路由注册
代码如下:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '',
name: 'Home',
component: Home,
children: [
{
path: '/',
component: r => require.ensure([], () => r(require('@/views/Index')), 'index')
},
{
path: '/newsuser/personal/:id',
component: r => require.ensure([], () => r(require('@/views/person/Personal')), 'personal'),
meta: {
requireLogin: true
},
children: [
{
// path: '/personal/info/:id',
path: '/newsuser/personal/info/:id',
name:'info',
component: r => require.ensure([], () => r(require('@/views/person/Info')), 'info')
},
{
path:'/newsuser/personal/myarticle/:id',
name:'myarticle',
component: r => require.ensure([], () => r(require('@/views/person/MyArticle')), 'myarticle')
},
{
path:'/newsuser/personal/mycollect/:id',
name:'mycollect',
component: r => require.ensure([], () => r(require('@/views/person/MyCollect')), 'mycollect')
},
{
path:'/newsuser/personal/myfan/:id',
name:'myfan',
component: r => require.ensure([], () => r(require('@/views/person/MyFanAndFollow')), 'myfan')
},
{
path:'/newsuser/personal/myfollow/:id',
name:'myfollow',
component: r => require.ensure([], () => r(require('@/views/person/MyFanAndFollow')), 'myfollow')
}
]
}
]
},
export default router
2.个人主页实现
Personal.vue:
<template>
<div>
<div class="PersonTop">
<div class="PersonTop_img">
<img v-image-preview :src="avatar" />
</div>
<div class="PersonTop_text">
<div class="user_text">
<div class="user_name">
<span> {{ nickname }} </span>
</div>
<div class="user-v" v-if="v === 3">
<img src="@/assets/img/V.png" class="user-v-img" />
<span class="user-v-font">优质媒体作者</span>
</div>
<div class="user_qianming">
<span> {{ design }}</span>
</div>
<div class="user_anniu">
<el-button
class="el-icon-edit"
v-if="this.$route.params.id === this.$store.state.id"
type="primary"
size="medium"
plain
@click="edit"
>编辑</el-button
>
<el-button
v-else
@click="follow"
type="primary"
size="medium"
icon="el-icon-check"
v-text="
isfollowid.indexOf(this.$route.params.id) > -1
? '已关注'
: '关注'
"
></el-button>
</div>
</div>
<div class="user_num">
<div style="cursor: pointer" @click="myfan">
<div class="num_number">{{ fanCounts }}</div>
<span class="num_text">粉丝</span>
</div>
<div style="cursor: pointer" @click="myfollow">
<div class="num_number">{{ followCounts }}</div>
<span class="num_text">关注</span>
</div>
<div>
<div class="num_number">{{ goodCounts }}</div>
<span class="num_text">获赞</span>
</div>
</div>
</div>
</div>
<div class="person_body">
<div class="person_body_left">
<el-card class="box-card" :body-style="{ padding: '0px' }">
<div slot="header" class="clearfix">
<span class="person_body_list" style="border-bottom: none"
>个人中心</span
>
</div>
<!-- <div
class="person_body_list"
v-for="(item, index) in person_body_list"
:key="index"
>
<router-link :to="{ name: item.name, params: item.params }">{{
item.label
}}</router-link>
</div> -->
<el-menu
router
active-text-color="#00c3ff"
class="el-menu-vertical-demo"
>
<el-menu-item
index="info"
:route="{ name: 'info', params: $route.params.id }"
>
<i class="el-icon-user"></i>
<span slot="title">个人简介</span>
</el-menu-item>
<el-menu-item
index="myarticle"
:route="{ name: 'myarticle', params: $route.params.id }"
>
<i class="el-icon-edit-outline"></i>
<span slot="title">发帖</span>
</el-menu-item>
<el-menu-item
index="mycollect"
:route="{ name: 'mycollect', params: $route.params.id }"
>
<i class="el-icon-document"></i>
<span slot="title">收藏</span>
</el-menu-item>
<el-menu-item
index="myfan"
:route="{ name: 'myfan', params: $route.params.id }"
>
<i class="el-icon-tableware"></i>
<span slot="title">粉丝</span>
</el-menu-item>
<el-menu-item
index="myfollow"
:route="{ name: 'myfollow', params: $route.params.id }"
>
<i class="el-icon-circle-plus-outline"></i>
<span slot="title">关注</span>
</el-menu-item>
</el-menu>
</el-card>
</div>
<div class="person_body_right">
<router-view></router-view>
</div>
</div>
<personal-dia ref="dia" @flesh="reload" />
</div>
</template>
<script>
import { userInfo } from "@/api/user";
import {
myFollow,
addFollow,
deleteFollow,
followAndFanCount,
} from "@/api/follow.js";
import { mygoodCount } from "@/api/good";
import PersonalDia from "./PersonalDia.vue";
export default {
components: { PersonalDia },
name: "Personal",
inject: ["reload"],
data() {
return {
avatar: "",
nickname: "",
v: 1,
design: "",
followCounts: "",
fanCounts: "",
goodCounts: "",
isfollow: true,
followData: {
fanId: "",
followId: "",
},
isfollowid: [],
};
},
mounted() {
this.load();
},
watch: {
$route(to, from) {
if (to.path == `/newsuser/personal/${this.$store.state.id}`) {
this.reload();
} else if (to.path == `/newsuser/personal/${this.$route.params.id}`) {
this.reload();
}
},
},
methods: {
load() {
userInfo(this.$route.params.id)
.then((res) => {
console.log(res);
this.avatar = res.data.avatar;
this.nickname = res.data.nickname;
this.v = res.data.v;
this.design = res.data.design;
})
.catch((err) => {
console.log(err);
});
myFollow(this.$store.state.id)
.then((res) => {
res.data.forEach((res) => {
this.isfollowid.push(res.id);
});
})
.catch((err) => {
console.log(err);
});
followAndFanCount(this.$route.params.id)
.then((res) => {
this.followCounts = res.data.followCounts;
this.fanCounts = res.data.fanCounts;
})
.catch((err) => {
console.log(err);
});
mygoodCount(this.$route.params.id)
.then((res) => {
this.goodCounts = res.data.goodCounts;
})
.catch((err) => {
console.log(err);
});
},
myfan() {
this.$router.push({
path: `/newsuser/personal/myfan/${this.$route.params.id}`,
});
},
myfollow() {
this.$router.push({
path:`/newsuser/personal/myfollow/${this.$route.params.id}`,
});
},
follow() {
if (!this.$store.state.id) {
this.$message({
showClose: true,
message: "请登录后再进行操作哦",
type: "warning",
});
} else {
this.followData.followId = this.$route.params.id;
this.followData.fanId = this.$store.state.id;
if (this.isfollowid.indexOf(this.followData.followId) > -1) {
this.isfollow = true;
} else {
this.isfollow = false;
}
if (this.isfollow) {
deleteFollow(this.followData)
.then((res) => {
this.isfollow = false;
this.$message({
showClose: true,
message: "已取消关注",
type: "success",
});
this.reload();
})
.catch((err) => {
console.log(err);
});
} else if (!this.isfollow) {
addFollow(this.followData)
.then((res) => {
this.isfollow = true;
this.$message({
showClose: true,
message: "已成功关注",
type: "success",
});
this.reload();
})
.catch((err) => {
console.log(err);
});
}
}
},
edit() {
this.$refs.dia.open();
},
},
};
</script>
<style scoped>
.me-video-player {
background-color: transparent;
width: 100%;
height: 100%;
object-fit: fill;
display: block;
position: fixed;
left: 0;
z-index: 0;
top: 0;
}
.PersonTop {
width: 1000px;
height: 140px;
padding-top: 20px;
background-color: white;
margin-top: 30px;
position: absolute;
left: 50%;
transform: translateX(-50%);
display: flex;
border-radius: 5px;
}
.PersonTop_img {
width: 150px;
height: 120px;
background-color: #8c939d;
margin-right: 24px;
margin-left: 20px;
overflow: hidden;
border-radius: 20px;
}
.PersonTop_img img {
width: 100%;
height: 100%;
border-radius: 20px;
}
.PersonTop_text {
height: 120px;
width: 880px;
display: flex;
}
.user_text {
width: 60%;
height: 100%;
line-height: 30px;
}
.user_name {
font-weight: bold;
}
.user-v {
margin-bottom: -5px;
}
.user-v-img {
width: 15px;
height: 15px;
}
.user-v-font {
font-size: 15px;
color: #00c3ff;
}
.user_qianming {
font-size: 14px;
color: #999;
}
.user_num {
width: 40%;
height: 100%;
display: flex;
align-items: center;
}
.user_num > div {
text-align: center;
border-right: 1px dotted #999;
box-sizing: border-box;
width: 80px;
height: 40px;
line-height: 20px;
}
.num_text {
color: #999;
}
.num_number {
font-size: 20px;
color: #333;
}
.el-menu-item>span {
font-size: 16px;
color: #999;
}
/*下面部分样式*/
.person_body {
width: 1000px;
margin-top: 210px;
display: flex;
position: absolute;
left: 50%;
transform: translateX(-50%);
border-radius: 5px;
}
.person_body_left {
width: 27%;
height: 600px;
border-radius: 5px;
margin-right: 3%;
text-align: center;
}
.person_body_list {
width: 100%;
height: 50px;
margin-top: 25px;
font-size: 22px;
border-bottom: 1px solid #f0f0f0;
background-image: -webkit-linear-gradient(
left,
rgb(42, 134, 141),
#e9e625dc 20%,
#3498db 40%,
#e74c3c 60%,
#09ff009a 80%,
rgba(82, 196, 204, 0.281) 100%
);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
-webkit-animation: masked-animation 4s linear infinite;
}
.el-menu-item {
margin-top: 22px;
}
.person_body_right {
width: 70%;
/* height: 500px; */
border-radius: 5px;
background-color: white;
}
.box-card {
height: 500px;
}
/*ui样式*/
.el-button {
width: 84px;
}
</style>
3.编辑弹窗按钮实现
效果图:
代码如下:
PersonalDia.vue:
<template>
<div>
<el-dialog
title="修改个人信息"
:visible.sync="dialogVisible"
width="60%"
:before-close="handleClose">
<el-form :model="form" :rules="rules" ref="form" label-width="150px">
<div class="updateinfo">
<div class="left">
<el-form-item label="头像" prop="avatar">
<img style="width:150px;height:110px" :src="form.avatar"></img>
</el-form-item>
<el-form-item label="账号密码" prop="password">
<el-input v-model="form.password"></el-input>
</el-form-item>
<el-form-item label="昵称" prop="nickname">
<el-input v-model="form.nickname"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model="form.age"></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-switch
v-model="form.sex"
active-color="#13ce66"
inactive-color="#ff4949"
active-text="男"
inactive-text="女"
:active-value= "1"
:inactive-value= "0"
>
</el-switch>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email"></el-input>
</el-form-item>
</div>
<div class="right">
<el-form-item label="用户编号" prop="id">
<el-input v-model="form.id" disabled></el-input>
</el-form-item>
<el-form-item label="账号" prop="account">
<el-input v-model="form.account" disabled></el-input>
</el-form-item>
<el-form-item label="地区" prop="area">
<el-input v-model="form.area"></el-input>
</el-form-item>
<el-form-item label="兴趣爱好" prop="hobby">
<el-input v-model="form.hobby"></el-input>
</el-form-item>
<el-form-item label="职业" prop="work">
<el-input v-model="form.work"></el-input>
</el-form-item>
<el-form-item label="个性签名" prop="design">
<el-input v-model="form.design"></el-input>
</el-form-item>
<el-form-item label="手机号码" prop="mobilePhoneNumber">
<el-input v-model="form.mobilePhoneNumber"></el-input>
</el-form-item>
</div>
</div>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submit">提 交</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { userInfo, updateUser } from "@/api/user.js";
export default {
name: "PersonalDia",
data() {
return {
dialogVisible: false,
form: {
avatar: "",
password: "",
nickname: "",
age: Number,
email: "",
mobilePhoneNumber: "",
sex: Number,
id: Number,
account: "",
area: "",
hobby: "",
work: "",
design: "",
},
rules: {
nickname: [
{ required: true, message: "昵称不能为空", trigger: "blur" },
],
password: [
{ required: true, message: "账号密码不能为空", trigger: "blur" },
],
},
};
},
mounted() {
this.load();
},
methods: {
open() {
this.dialogVisible = true;
},
load() {
userInfo(this.$store.state.id)
.then((res) => {
console.log(res);
Object.assign(this.form, res.data);
})
.catch((err) => {
console.log(err);
});
},
submit() {
updateUser(this.form)
.then((res) => {
console.log(res);
this.dialogVisible = false;
this.$emit("flesh");
})
.catch((err) => {
console.log(err);
});
},
handleClose() {
this.dialogVisible = false;
this.$emit("flesh");
},
},
};
</script>
<style scoped>
.updateinfo {
height: 350px;
overflow: auto;
}
.left {
/* width: 330px; */
float: left;
}
.right {
overflow: hidden;
}
</style>
4.个人简介实现
效果图:
代码如下:
Info.vue:
<template>
<div>
<el-card>
<el-descriptions class="margin-top" title="简介" :column="2" border>
<template slot="extra">
<el-button type="primary" v-if="$route.params.id==$store.state.id" size="small">操作</el-button>
</template>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-picture-outline"></i>
头像
</template>
<img class="img" :src="avatar" alt="" />
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-user"></i>
账户名
</template>
{{ account }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-s-custom"></i>
昵称
</template>
{{ nickname }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-odometer"></i>
年龄
</template>
{{ age }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-male"></i>
<i class="el-icon-female"></i>
性别
</template>
<el-tag size="small">{{ sex }}</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-message"></i>
邮箱Email
</template>
{{ email }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
手机号码
</template>
{{ mobilePhoneNumber }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-location-outline"></i>
地区
</template>
{{ area }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
职业
</template>
{{ work }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-basketball"></i>
兴趣爱好
</template>
{{ hobby }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-magic-stick"></i>
个性签名
</template>
{{ design }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-date"></i>
注册日期
</template>
{{ createDate | formatDate }}
</el-descriptions-item>
</el-descriptions>
</el-card>
</div>
</template>
<script>
import { userInfo } from "@/api/user.js";
export default {
name: "Info",
data() {
return {
avatar: String,
account: String,
age: Number,
email: String,
mobilePhoneNumber: String,
area: String,
createDate: Number,
nickname: String,
sex: String,
work: String,
hobby: String,
design: String,
};
},
mounted() {
this.load();
},
methods: {
load() {
userInfo(this.$route.params.id)
.then((res) => {
this.avatar = res.data.avatar;
this.account = res.data.account;
this.age = res.data.age;
this.email = res.data.email;
this.mobilePhoneNumber = res.data.mobilePhoneNumber;
this.area = res.data.area;
this.createDate = res.data.createDate;
this.nickname = res.data.nickname;
this.sex = res.data.sex == 1 ? "男" : "女";
this.work = res.data.work;
this.design = res.data.design;
this.hobby = res.data.hobby;
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
<style scoped>
.img {
width: 80px;
height: 80px;
}
</style>
5.发贴页实现
效果图:
代码:
MyArticle.vue:
<template>
<div class="myart1">
<article-item v-for="a in allData" :key="a.id" v-bind="a"/>
<el-empty
v-if="allData.length == 0"
:image-size="250"
description="暂未发表任何新闻额"
></el-empty>
</div>
</template>
<script>
import { myArticle } from "@/api/user.js";
import ArticleItem from '../../components/article/ArticleItem.vue';
export default {
components: { ArticleItem },
name: "MyArticle",
data() {
return {
allData:[]
};
},
mounted() {
this.load();
},
methods: {
load() {
myArticle(this.$route.params.id)
.then((res) => {
console.log(res);
this.allData=res.data
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
<style>
.myart1{
line-height: 30px;
}
</style>
6.收藏页实现
效果图:
代码:
MyCollect.vue:
<template>
<div class="myart1">
<article-item v-for="a in allData" :key="a.id" v-bind="a"/>
<el-empty
v-if="allData.length == 0"
:image-size="250"
description="暂未收藏任何新闻额"
></el-empty>
</div>
</template>
<script>
import { myCollect } from "@/api/collect.js";
import ArticleItem from '../../components/article/ArticleItem.vue';
export default {
components: { ArticleItem },
name: "MyCollect",
data() {
return {
allData:[]
};
},
mounted() {
this.load();
},
methods: {
load() {
myCollect(this.$route.params.id)
.then((res) => {
console.log(res);
res.data.forEach(element => {
element.createDate=this.$options.filters['formatDate'](parseInt(element.createDate))
});
this.allData=res.data
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
<style>
.el-card {
border-radius: 0;
}
.el-card:not(:first-child) {
margin-top: 5px;
}
.myart1{
line-height: 30px;
}
</style>
7.关注和收藏页实现
效果图:
代码:
MyFanAndFollow.vue:
<template>
<div class="fanorfollow_box">
<div class="fanorfollow" v-for="(item, index) in allData">
<div class="fanorfollow_left">
<img class="fanorfollow_img" v-image-preview :src="item.avatar" />
</div>
<div class="fanorfollow_info">
<div class="fanorfollow_info_top">
<span
style="color: #666; max-width: 180px"
@click="personal(item.id)"
>{{ item.nickname }}</span
>
</div>
<div class="fanorfollow_info_bottom">
<span @click="personal(item.id)">{{ item.design }}</span>
</div>
</div>
<div class="fanorfollow_botton">
<el-button
@click="follow(item.id)"
type="primary"
size="small"
round
icon="el-icon-check"
v-text="isfollowid.indexOf(item.id) > -1 ? '已关注' : '关注'"
></el-button>
</div>
</div>
<div>
<el-empty
v-if="allData.length == 0"
:image-size="250"
description="这里什么都没有哟"
></el-empty>
</div>
</div>
</template>
<script>
import { myFollow, myFan, addFollow, deleteFollow } from "@/api/follow.js";
export default {
name: "MyFanAndFollow",
inject: ["reload"],
data() {
return {
allData: [],
isfollow: true,
followData: {
fanId: "",
followId: "",
},
isfollowid: [],
};
},
watch: {
$route(to, from) {
if (to.path == `/newsuser/personal/myfan/${this.$route.params.id}`) {
myFan(this.$route.params.id)
.then((res) => {
console.log(res);
this.allData = res.data;
myFollow(this.$route.params.id).then((res) => {
res.data.forEach((element) => {
this.isfollowid.push(element.id);
});
});
})
.catch((err) => {
console.log(err);
});
} else {
myFollow(this.$route.params.id)
.then((res) => {
console.log(res);
this.allData = res.data;
res.data.forEach((element) => {
this.isfollowid.push(element.id);
});
})
.catch((err) => {
console.log(err);
});
}
},
},
mounted() {
this.load();
},
methods: {
load() {
if (
this.$route.path == `/newsuser/personal/myfan/${this.$route.params.id}`
) {
myFan(this.$route.params.id)
.then((res) => {
console.log(res);
this.allData = res.data;
myFollow(this.$route.params.id).then((res) => {
res.data.forEach((element) => {
this.isfollowid.push(element.id);
});
});
})
.catch((err) => {
console.log(err);
});
} else {
myFollow(this.$route.params.id)
.then((res) => {
console.log(res);
this.allData = res.data;
res.data.forEach((element) => {
this.isfollowid.push(element.id);
});
})
.catch((err) => {
console.log(err);
});
}
},
follow(id) {
if (!this.$store.state.id) {
this.$message({
showClose: true,
message: "请登录后再进行操作哦",
type: "warning",
});
return;
}
if (this.$store.state.id != this.$route.params.id) {
this.$message({
showClose: true,
message: "此页面不是你的个人中心哦",
type: "warning",
});
return;
}
this.followData.followId = id;
this.followData.fanId = this.$store.state.id;
if (this.isfollowid.indexOf(this.followData.followId) > -1) {
this.isfollow = true;
} else {
this.isfollow = false;
}
if (this.isfollow) {
deleteFollow(this.followData)
.then((res) => {
console.log(res.data);
this.isfollow = false;
this.$message({
showClose: true,
message: "已取消关注",
type: "success",
});
this.reload();
})
.catch((err) => {
console.log(err);
});
} else if (!this.isfollow) {
addFollow(this.followData)
.then((res) => {
console.log(res.data);
this.isfollow = true;
this.$message({
showClose: true,
message: "已成功关注",
type: "success",
});
this.reload();
})
.catch((err) => {
console.log(err);
});
}
},
personal(id) {
this.$router.push({ path: `/newsuser/personal/${id}` });
},
},
};
</script>
<style>
.fanorfollow_box :hover {
border-width: 1px;
border-color: deepskyblue;
}
.fanorfollow {
padding: 15px 40px 15px 30px;
height: 50px;
display: flex;
align-items: center;
border: 1px solid #ebebeb;
}
.fanorfollow :hover {
border-width: 1px;
border-color: deepskyblue;
}
.fanorfollow_left {
width: 60px;
height: 60px;
}
.fanorfollow_img {
width: 100%;
height: 100%;
border-radius: 50%;
border: 1px solid #ebebeb;
vertical-align: top;
}
.fanorfollow_info {
display: inline-block;
margin-left: 20px;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
overflow: hidden;
}
.fanorfollow_info_top {
display: inline-block;
font-size: 10;
line-height: 14px;
vertical-align: top;
cursor: pointer;
}
.fanorfollow_info_top :hover {
color: deepskyblue;
}
.fanorfollow_info_bottom {
line-height: 14px;
color: #999;
margin-top: 5px;
cursor: pointer;
}
.fanorfollow_info_bottom :hover {
color: deepskyblue;
}
</style>
四、总结
差不多就这些,关注我后续会有更多精彩内容