如果想看该实战系列的其他内容,请移步至 Vue.js 实战系列之实现视频类WebApp的项目开发。
项目仓库地址,欢迎 Star
实现效果
功能实现
-
“我的”界面设计
mine/index.vue
<template> <div class="mine"> <!-- 顶部背景模块 --> <div class="mine-top" :style="bgPic"> <!-- 右上角菜单按钮 --> <div class="menu-box"> <span class="iconfont icon-caidan"></span> </div> </div> <!-- 个人信息模块 --> <div class="mine-wrap"> <div class="mine-content"> <!-- 头像行 --> <div class="info"> <img src="@/assets/images/mine/tx.png" style=" height: 100px; width: 100px; border-radius: 50%; margin-right: 20px; " /> <div class="info-right"> <button class="btn">编辑资料</button> <button class="btn"> <span class="iconfont icon-jiahao1"></span> 朋友 </button> </div> </div> <!-- 用户信息 --> <div class="desc"> <h2>前端小新</h2> <p class="dyh"> 抖音号:98579335 <span class="iconfont icon-erweima"></span> </p> <p class="jj">没有好看的皮囊,但有有趣的灵魂,技术没有止境</p> </div> <!-- 用户标签 --> <div class="user-tag"> <span> <span class="iconfont icon-touxiang"></span> 23岁 </span> <span>中国</span> <span><span class="iconfont icon-jiahao1"></span>添加学校等标签</span> </div> <div class="user-tag2"> <span><a>2</a>获赞</span> <span><a>543</a>关注</span> <span><a>1087</a>粉丝</span> </div> </div> </div> <!-- 内容切换 --> <div class="mine-tab"> <div class="tab-navbar"> <div class="item" @click="changeTab(0)" :class="indexTab === 0 ? 'active' : '' ">作品</div> <div class="item" @click="changeTab(1)" :class="indexTab === 1 ? 'active' : '' ">私密<span class="iconfont icon-suo"></span></div> <div class="item" @click="changeTab(2)" :class="indexTab === 2 ? 'active' : '' ">喜欢<span class="iconfont icon-suo"></span></div> </div> <div class="tab-wrap"> <!-- 作品 --> <div class="tab-con" v-show="indexTab === 0"> <div class="tab-img" v-for="i in 10" :key="i"> <img src="@/assets/images/mine/bj.png" style="width:100%;height:auto" > </div> </div> <!-- 私密 --> <div class="tab-con" v-show="indexTab === 1"> <div class="tab-con2"> <h3>没有私密作品</h3> <p>设为私密的作品和过期的日记会出现在这里,并且只有你能看到</p> </div> <!-- <div class="tab-img" v-for="i in 10" :key="i"> <img src="@/assets/images/mine/bj2.png" style="width:100%;height:auto" > </div> --> </div> <!-- 喜欢 --> <div class="tab-con" v-show="indexTab === 2"> <div class="tab-con3">只有你能看到自己的喜欢列表</div> <div class="tab-img" v-for="i in 10" :key="i"> <img src="@/assets/images/mine/bj3.png" style="width:100%;height:auto" > </div> </div> </div> </div> </div> </template> <script> export default { data() { return { bgPic: { backgroundImage: `url(${ require('@/assets/images/mine/bj.png')})`, backgroundRepeat: 'no-repeat', backgroundSize: '100% 100%', }, indexTab: 0, }; }, methods: { changeTab(index) { this.indexTab = index; }, }, }; </script> <style lang="less" scoped> .mine { .mine-top { height: 160px; display: flex; justify-content: flex-end; padding: 20px; .menu-box { width: 35px; height: 35px; border-radius: 50%; background: rgba(0, 0, 0, 0.3); display: flex; align-items: center; justify-content: center; .icon-caidan { color: #ffffff; font-size: 20px; } } } .mine-wrap { position: relative; // top: 180px; width: 100%; background-color: #101821; color: #ffffff; .mine-content { padding: 0 15px; .info { position: relative; top: -25px; display: flex; align-items: center; justify-content: space-between; .info-right { button { font-size: 17px; letter-spacing: 2px; height: 40px; width: 120px; padding: 0 2px; background-color: #393842; border: none; color: #ffffff; margin-left: 10px; } } } .desc { margin-top: -20px; h2 { font-size: 20px; } .dyh { font-size: 13px; height: 20px; line-height: 20px; padding: 5px 0 25px 0; color: rgb(163, 163, 163); .icon-erweima { font-size: 18px; font-weight: 600; } } .jj { font-size: 14px; } } .user-tag { height: 30px; margin-top: 0; font-size: 14px; color: #969696; span { margin-right: 5px; background: rgba(85, 85, 85, 0.6); padding: 5px 8px; .icon-touxiang { width: 10px; height: 10px; color: rgb(5, 224, 224); background-color: rgba(0, 0, 0, 0); margin: 0; padding: 0; } .icon-jiahao1 { background-color: rgba(0, 0, 0, 0); margin: 0; padding: 0; } } } .user-tag2 { padding: 15px 0; color: #9e9e9e; span { font-size: 16px; margin-right: 15px; } a { font-size: 18px; color: #ffffff; font-weight: 600; margin-right: 5px; } } } } .mine-tab { margin-top: -1px; height: 300px; width: 100%; background-color: #101821; .tab-navbar { padding-top: 10px; display: flex; justify-content: space-around; align-items: center; .item { font-size: 16px; padding: 10px; flex: 1; text-align: center; color: #686868; .icon-suo { font-size: 14px; margin-left: 5px; } } .active { border-bottom: 2px solid #ffdf03; color: #ffffff; font-weight: 600; } } .tab-wrap { background-color: #101821; padding-top: 5px; .tab-con { display: flex; flex-direction: row; justify-content: space-between; flex-wrap: wrap; .tab-img { width: 33%; &:nth-child(3n) { border-right: 0; } } .tab-con1 { color: #a1a1a1; width: 100%; height: 200px; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 0 40px; h3 { color: #f3f3f3; font-size: 18px; font-weight: normal; } } .tab-con2 { color: #a1a1a1; width: 100%; height: 200px; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 0 40px; h3 { color: #f3f3f3; font-size: 18px; font-weight: normal; } p { margin-top: 0; font-size: 15px; text-align: center; line-height: 1.3; } } .tab-con3 { font-size: 14px; color: #a1a1a1; width: 100%; height: 50px; text-align: center; line-height: 50px; } } } } } </style>
-
使用 mock 数据创建用户信息
在
public/static
新建userInfo.json
文件如果不知道为什么要在 public 下面创建该文件,请移步至:10. 本地mock数据实现数据请求 查看。
{ "userInfo": { "name": "前端小新", "dyh": 98579335, "desc": "没有好看的皮囊,但有有趣的灵魂,技术没有止境", "age": 23, "region": "中国", "tag": [], "like": 2, "follow": 543, "fans": 1087, "vlist": { "works": [], "private": [], "likes": [] } } }
-
Vuex 的 modules 进行模块化数据处理
在前两个章节中我们引入了 Vuex 进行状态管理,在这里,我们继续使用它来对用户的信息进行管理。
我们使用
axios
请求本地 json 数据来模拟后端的数据请求,实现用户个人信息的获取。- 在
src/store/modules
下,新建user.js
import { GET } from '@/request/http'; const user = { namespaced: true, state: { userInfo: { }, }, mutations: { assignUseInfo(state, res) { state.userInfo = res.userInfo; }, }, actions: { GetUserInfo({ state, commit }, params) { GET('/static/userInfo.json') .then(res => { console.log(res.data); commit('assignUseInfo', res.data); // 将请求到的数据赋值给vuex中的state }); }, }, }; export default user;
- 模块创建完成之后不要忘记将该模块导出,在
src/store/index.js
中导入才可以使用
import Vue from 'vue'; import Vuex from 'vuex'; import sign from './modules/sign'; import user from './modules/user'; Vue.use(Vuex); export default new Vuex.Store({ ... modules: { user, sign, }, });
- Vuex 处理完之后就可以在页面中执行该请求方法了
<script> import { mapActions } from 'vuex'; export default { data() { return { ... }; }, created() { this.getUserInfo(); }, methods: { ...mapActions('user', ['GetUserInfo']), // 获取用户数据 getUserInfo() { this.GetUserInfo(); }, }, }; </script>
- 完整实现
<template> <div class="mine"> <!-- 顶部背景模块 --> <div class="mine-top" :style="bgPic"> <!-- 右上角菜单按钮 --> <div class="menu-box"> <span class="iconfont icon-caidan"></span> </div> </div> <!-- 个人信息模块 --> <div class="mine-wrap"> <div class="mine-content"> <!-- 头像行 --> <div class="info"> <img :src="userInfo.avathor" style=" height: 100px; width: 100px; border-radius: 50%; margin-right: 20px; " /> <div class="info-right"> <button class="btn">编辑资料</button> <button class="btn"> <span class="iconfont icon-jiahao1"></span> 朋友 </button> </div> </div> <!-- 用户信息 --> <div class="desc"> <h2>{ { userInfo.name }}</h2> <p class="dyh"> 抖音号:{ { userInfo.dyh }} <span class="iconfont icon-erweima"></span> </p> <p class="jj">{ { userInfo.desc }}</p> </div> <!-- 用户标签 --> <div class="user-tag"> <span> <span class="iconfont icon-touxiang"></span> { { userInfo.age }}岁 </span> <span>{ { userInfo.region }}</span> <span><span class="iconfont icon-jiahao1"></span>添加学校等标签</span> </div> <div class="user-tag2"> <span ><a>{ { userInfo.like }}</a >获赞</span > <span ><a>{ { userInfo.follow }}</a >关注</span > <span ><a>{ { userInfo.fans }}</a >粉丝</span > </div> </div> </div> <!-- 内容切换 --> <div class="mine-tab"> <div class="tab-navbar"> <div class="item" @click="changeTab(0)" :class="indexTab === 0 ? 'active' : ''" > 作品 </div> <div class="item" @click="changeTab(1)" :class="indexTab === 1 ? 'active' : ''" > 私密<span class="iconfont icon-suo"></span> </div> <div class="item" @click="changeTab(2)" :class="indexTab === 2 ? 'active' : ''" > 喜欢<span class="iconfont icon-suo"></span> </div> </div> <div class="tab-wrap"> <!-- 作品 --> <div class="tab-con" v-show="indexTab === 0"> <div class="tab-con1" :v-if="userInfo.vlist.works.length === 0"> <h3>暂无作品</h3> </div> <div class="tab-img" :v-if="userInfo.vlist.works.length !== 0" v-for="i in userInfo.vlist.works" :key="i" > <img src="@/assets/images/mine/bj.png" style="width: 100%; height: auto" /> </div> </div> <!-- 私密 --> <div class="tab-con" v-show="indexTab === 1"> <div class="tab-con2" :v-if="userInfo.vlist.private.length === 0"> <h3>没有私密作品</h3> <p>设为私密的作品和过期的日记会出现在这里,并且只有你能看到</p> </div> <div class="tab-img" v-for="i in userInfo.vlist.private" :key="i"> <img src="@/assets/images/mine/bj2.png" style="width: 100%; height: auto" /> </div> </div> <!-- 喜欢 --> <div class="tab-con" v-show="indexTab === 2"> <div class="tab-con1" :v-if="userInfo.vlist.likes.length === 0"> <h3>空空如也</h3> </div> <div> <div class="tab-con3">只有你能看到自己的喜欢列表</div> <div class="tab-img" :v-if="userInfo.vlist.likes.length !== 0" v-for="i in userInfo.vlist.likes" :key="i"> <img src="@/assets/images/mine/bj3.png" style="width: 100%; height: auto" /> </div> </div> </div> </div> </div> </div> </template> <script> import { mapActions, mapState } from 'vuex'; export default { data() { return { bgPic: { backgroundImage: `url(${ require('@/assets/images/mine/bj.png')})`, backgroundRepeat: 'no-repeat', backgroundSize: '100% 100%', }, indexTab: 0, }; }, created() { // 获取用户数据 this.GetUserInfo(); }, // 计算属性,监控userInfo computed: { ...mapState({ userInfo: (state) => state.user.userInfo, }), }, methods: { ...mapActions('user', ['GetUserInfo']), changeTab(index) { this.indexTab = index; }, }, }; </script>
- 在
总结
本章节需要注意的几个点:
- Vuex 状态管理
computed
计算属性
上一章节: 13. 自定义全局弹出框组件的实现
下一章节: 15. 用户信息编辑页面的实现
项目整体介绍:Vue.js 项目实战之实现视频播放类WebApp的项目开发(仿抖音app)
项目仓库地址,欢迎 Star。
有任何问题欢迎评论区留言讨论。
转载:https://blog.csdn.net/XH_jing/article/details/117289846
查看评论