保姆级全栈项目BBS 开发实录 第二章:前端基础页面
bbs,中文全称是电子公告板系统,提供了一块公共的电子公告板,让用户可以在上面发布信息、交流、讨论。本系列博客,带大家使用若依来编写一个bbs,包含帖子、长文、视频、投票发布,用户生成内容发布后百度云智能审核与违规词库等……逐步逐句地深入浅出,是新手学习的不二之选
·
第二章:写作按钮、底部导航栏和顶部侧滑头像
- 本章结束后实现的效果
1、基本的页面文件结构
- 根据原型图来创建有的基础页面,下面操作能够实现不用输入代码就能在路由中注册页面路径
- 然后就能发现在pages中,出现新的页面路径
创建好如以下页面的页面结构
https://www.iconfont.cn/
2、使用tabBar实现底部导航栏
- 这个是说你页面没有被使用,不用担心的
- 想要解决也很简单
- 先复制下面的代码,然后加上关闭过滤无依赖文件
// 关闭过滤无依赖文件功能
"disableDependencyAnalysis": true
pages.json代码
{
"pages": [
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/message/message",
"style": {
"navigationBarTitleText": "message"
}
},
{
"path": "pages/organizations/organizations",
"style": {
"navigationBarTitleText": "organizations"
}
},
{
"path": "pages/test/test",
"style": {
"navigationBarTitleText": "test"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
// 底部导航栏
"color": "#333333",
"selectedColor": "#333333",
"backgroundColor": "#ffffff",
"borderStyle": "white",
"list": [
{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home.png"
},
{
"text": "组织",
"pagePath": "pages/organizations/organizations",
"iconPath": "static/tabbar/organizations.png",
"selectedIconPath": "static/tabbar/organizations.png"
},
{
"text": "消息",
"pagePath": "pages/message/message",
"iconPath": "static/tabbar/news.png",
"selectedIconPath": "static/tabbar/news.png"
},
{
"text": "test",
"pagePath": "pages/test/test",
"iconPath": "static/logo.png",
"selectedIconPath": "static/logo.png"
}
]
}
}
3、编写写作按钮
导入按钮本身
<!-- 我是一个写作按钮 -->
<template>
<view class="container">
<!-- 页面其他内容 -->
<image class="add-button" :src="buttonImage" @click="handleClick"></image>
</view>
</template>
<script setup lang="ts">
import { ref, computed, nextTick } from 'vue'
// 定义响应式变量
const isAddButton1 = ref(true)
// 切换图片和跳转页面的方法
const handleClick = () => {
isAddButton1.value = !isAddButton1.value
// 如果切换后的状态是 AddButton1,进行页面跳转
if (isAddButton1.value) {
nextTick(() => {
setTimeout(() => {
uni.navigateTo({
url: '/pages/writing/writing',
fail: (err) => {
console.error('Navigation Error:', err)
},
})
}, 100) // 延迟时间可以根据实际需要调整
})
}
}
// 预加载图片
function preloadImage(src: string) {
if (typeof Image !== 'undefined') {
const img = new Image()
img.src = src
} else {
console.warn('Image is not defined in this environment')
}
}
// 预加载图片
preloadImage('/static/add/AddButton1.png')
preloadImage('/static/add/AddButton2.png')
// 图片路径的计算属性
const buttonImage = computed(() =>
isAddButton1.value ? '/static/add/AddButton1.png' : '/static/add/AddButton2.png',
)
</script>
<style scoped>
.container {
position: relative;
width: 100%;
height: 100vh;
background-color: #f0f0f0;
}
.add-button {
position: fixed;
right: 5%; /* 调整按钮的水平位置 */
bottom: 5%; /* 调整按钮的位置,使其在导航栏上方 */
width: 20vw; /* 相对屏幕宽度的按钮宽度 */
height: 20vw; /* 相对屏幕宽度的按钮高度 */
cursor: pointer;
}
</style>
- 这个按钮会用到两张图片
导入writing代码
<!-- 我是写作页 后面使用富文本插件 -->
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
// 使用路由
const router = useRouter()
// 定义响应式变量
const title = ref('')
const content = ref('')
// 计算属性,判断发帖按钮是否可点击
const canPost = computed(() => title.value.trim() !== '' && content.value.trim() !== '')
// 返回原本页面
const goBack = () => {
uni.navigateBack()
}
// 发帖方法
const postArticle = () => {
if (canPost.value) {
// 发帖逻辑示例
console.log('发帖', { title: title.value, content: content.value })
// 发帖成功后,可以进行页面跳转等操作
}
}
// 选择图片方法
const chooseImage = () => {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
console.log('选择的图片', res.tempFilePaths)
},
})
}
</script>
<template>
<view class="container">
<!-- 顶部导航栏 -->
<view class="navbar">
<text class="back-button" @click="goBack">X</text>
</view>
<!-- 输入框 -->
<view class="input-container">
<input
class="title-input"
type="text"
:maxlength="120"
placeholder="输入标题..."
v-model="title"
/>
<textarea
class="content-input"
:maxlength="100000"
placeholder="输入内容..."
v-model="content"
></textarea>
</view>
<!-- 底部图标按钮 -->
<view class="bottom-bar">
<view class="button-container">
<view class="post-button-container">
<button
class="post-button"
:disabled="!canPost"
@click="postArticle"
:class="{ active: canPost }"
>
发帖
</button>
</view>
<button class="image-button" @click="chooseImage">图片</button>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
.container {
display: flex;
flex-direction: column;
height: 100vh;
padding: 10rpx;
margin-top: 30rpx; /* 上边框外边距 */
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
}
.back-button {
font-size: 40rpx;
}
.post-button-container {
margin-left: auto;
}
.post-button {
background-color: #007bff;
border-radius: 50rpx;
padding: 10rpx 20rpx;
color: white;
font-size: 32rpx;
border: none;
opacity: 0.5;
transition: opacity 0.3s;
}
.post-button:enabled {
opacity: 1;
}
.post-button.active {
opacity: 1;
}
.input-container {
display: flex;
flex-direction: column;
margin-top: 20rpx;
}
.title-input,
.content-input {
font-size: 32rpx;
border: none;
border-radius: 10rpx;
padding: 10rpx;
}
.title-input {
height: 80rpx;
margin-bottom: 20rpx;
}
.content-input {
flex: 1;
min-height: 300rpx; /* 最小高度,确保可以完整显示内容 */
margin-bottom: 20rpx; /* 底部留白 */
}
.bottom-bar {
display: flex;
justify-content: center;
padding: 20rpx;
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
box-shadow: 0 -2rpx 5rpx rgba(0, 0, 0, 0.1); /* 添加底部阴影效果 */
margin-bottom: 20rpx; /* 下边框外边距 */
}
.button-container {
display: flex;
justify-content: space-between;
width: 100%;
}
.button-container .post-button {
background-color: #007bff;
border-radius: 50rpx;
padding: 10rpx 20rpx;
color: white;
font-size: 32rpx;
border: none;
}
.button-container .image-button {
background-color: #007bff;
border-radius: 50rpx;
padding: 10rpx 20rpx;
color: white;
font-size: 32rpx;
border: none;
}
</style>
报错解决
pnpm install vue-router --save
# 安装 vue-router 的类型声明
pnpm install @types/vue-router --save-dev
index页面导入组件
<script setup lang="ts">
import AddButton from '@/components/AddButton.vue'
</script>
<template>
<AddButton />
</template>
<style></style>
解决顶部不是自定义导航栏问题
"navigationStyle": "custom",
https://cdn.jsdelivr.net/gh/Qiu-JW/NotePicture/2024/08/image-20240806215014105.png
- 也加上那行代码
在这里插入图片描述
- 最终效果
4、引入编写侧滑头像组件
- 因为我们要实现得效果如下图
- 想要实现这个效果,就要引入uni-ui。自己能手写出来,但使用组件会更快
- 我们已经导入过uni-ui的依赖,因此想要使用uniapp的组件有两种方法
方法一 这样一个个导入
方法二 配置自动导入规则
- 具体看uniapp的官网,这里能看到使用uniui的详细配置
https://zh.uniapp.dcloud.io/component/uniui/quickstart.html
npm i sass -D
npm i sass-loader@10.1.1 -D
npm i @dcloudio/uni-ui
// pages.json
{
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
// 其他内容
pages:[
// ...
]
}
- 然后就可以使用插件了
<uni-card>
<text>这是一个基础卡片示例,内容较少,此示例展示了一个没有任何属性不带阴影的卡片。</text>
</uni-card>
抽象问题- 样式未生效
- 你可以会看到这样的场景,这是因为你的依赖里面有uniapp自动导入的依赖(按道理来说应该没有依赖才不显示,但uniapp就不一样了)
{
"name": "fuxincampusconnect",
"version": "0.0.0",
"author": {
"name": "Qiuner"
},
"keywords": [
"福信校园通"
],
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"dev:app": "uni -p app",
"dev:app-android": "uni -p app-android",
"dev:app-ios": "uni -p app-ios",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:mp-xhs": "uni -p mp-xhs",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:app": "uni build -p app",
"build:app-android": "uni build -p app-android",
"build:app-ios": "uni build -p app-ios",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-jd": "uni build -p mp-jd",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:mp-xhs": "uni build -p mp-xhs",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-app-plus": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-components": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-h5": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-jd": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-mp-xhs": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-ui": "^1.5.5",
"pinia": "2.0.27",
"pinia-plugin-persistedstate": "^3.2.0",
"vue": "^3.2.47",
"vue-i18n": "^9.2.2",
"vue-router": "^4.4.2"
},
"devDependencies": {
"@dcloudio/types": "^3.3.3",
"@dcloudio/uni-automator": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3081220230802001",
"@dcloudio/uni-vue-devtools": "3.0.0-alpha-3080220230511001",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3081220230802001",
"@rushstack/eslint-patch": "^1.1.4",
"@types/node": "^18.11.9",
"@types/vue-router": "^2.0.0",
"@uni-helper/uni-app-types": "^0.5.8",
"@uni-helper/uni-ui-types": "^0.5.11",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/runtime-core": "^3.2.45",
"@vue/tsconfig": "^0.4.0",
"eslint": "^8.22.0",
"eslint-plugin-vue": "^9.3.0",
"husky": "^8.0.0",
"lint-staged": "^13.0.3",
"miniprogram-api-typings": "^3.12.0",
"prettier": "^2.7.1",
"sass": "^1.77.8",
"sass-loader": "10.1.1",
"typescript": "^5.1.6",
"vite": "^4.4.9",
"vue-tsc": "^1.8.8"
}
}
- 将以上依赖复制到package.json中即可、
导入其他代码
TabHeader
<script setup lang="ts">
import { ref } from 'vue'
import uniPopup from '@dcloudio/uni-ui/lib/uni-popup/uni-popup.vue'
import PopupContent from '@/components/HeadPortrait/HeadPopupContent.vue'
const currentTab = ref('whole')
const changeTab = (tab: string) => {
currentTab.value = tab
}
const popup: Ref<InstanceType<typeof uniPopup> | null> = ref(null)
const openPopup = () => {
if (popup.value) {
popup.value.open()
}
}
const closePopup = () => {
if (popup.value) {
popup.value.close()
}
}
const props = defineProps({
type: {
type: Number,
required: true,
},
})
// 存储输入的搜索关键字
const searchKeyword = ref('')
// 处理搜索确认事件 TODO类型判断
const search = (event: { detail: { value: any } }) => {
const keyword = event.detail.value
console.log('搜索关键词:', keyword)
// 搜索逻辑
}
// 处理输入事件
const input = (event: { detail: { value: string } }) => {
searchKeyword.value = event.detail.value
console.log('当前输入:', searchKeyword.value)
// 输入逻辑
}
</script>
<template>
<view class="navbar">
<view class="logo">
<view class="avatar-container" @click="openPopup">
<image class="head-portrait-image" src="/static/logo.png"></image>
</view>
<template v-if="type === 2">
<text class="logo-image">消息</text>
</template>
<template v-if="type === 3">
<uni-search-bar :radius="100" @confirm="search"></uni-search-bar>
</template>
</view>
<view class="header">
<view class="tab-container">
<template v-if="type === 2">
<view class="tab" :class="{ active: currentTab === 'whole' }" @click="changeTab('whole')">
<text>全部</text>
</view>
<view
class="tab"
:class="{ active: currentTab === 'interaction' }"
@click="changeTab('interaction')"
>
<text>互动</text>
</view>
<view
class="tab"
:class="{ active: currentTab === 'follow' }"
@click="changeTab('follow')"
>
<text>关注</text>
</view>
</template>
<template v-else-if="type === 1">
<view class="tab" :class="{ active: currentTab === 'whole' }" @click="changeTab('whole')">
<text>为您推荐</text>
</view>
<view
class="tab"
:class="{ active: currentTab === 'interaction' }"
@click="changeTab('interaction')"
>
<text>正在关注</text>
</view>
</template>
</view>
</view>
<uni-popup ref="popup" type="left" :style="{ width: '80%' }">
<PopupContent @close="closePopup" />
</uni-popup>
</view>
</template>
<style lang="scss">
/* 自定义导航条 */
.navbar {
background-size: cover;
position: relative;
display: flex;
flex-direction: column;
padding-top: 20px;
.logo {
display: flex;
align-items: center;
height: 100rpx; /* 增加导航栏的高度 */
padding-left: 30rpx;
padding-top: 20rpx;
.avatar-container {
margin-right: 20rpx;
}
.head-portrait-image {
width: 80rpx; /* 增加头像的大小 */
height: 80rpx; /* 增加头像的大小 */
border-radius: 50%;
cursor: pointer;
}
.logo-image {
line-height: 28rpx;
color: #000;
margin-left: 28rpx;
padding-left: 20rpx;
font-size: 45rpx;
}
}
.header {
display: flex;
flex-direction: row;
align-items: center;
padding: 10px;
background-color: #fff;
border-bottom: 1px solid #eee;
}
.tab-container {
flex: 1;
display: flex;
justify-content: space-around;
}
.tab {
flex: 1;
text-align: center;
padding: 5px 0;
cursor: pointer;
}
.tab.active {
border-bottom: 2px solid blue;
font-weight: bold;
}
}
</style>
HeadPopupContent
<script setup lang="ts">
import { defineEmits } from 'vue'
const emit = defineEmits(['close'])
const goToEditing = () => {
// 使用uniapp的导航方法跳转到指定页面
uni.navigateTo({
url: '/components/HeadPortrait/profile',
})
}
</script>
<template>
<view class="popup-content">
<view class="profile-section">
<image class="profile-image" src="/static/logo.png"></image>
<!-- TODO 和后端获取账号 -->
<view class="profile-name">Qiuner</view>
<!-- TODO 和后端获取账号 -->
<view class="profile-username">@wsjw3635</view>
</view>
<view class="profile-stats">
<!-- TODO 和后端交互 -->
<view>3 正在关注 0 关注者</view>
</view>
<view class="menu-items">
<view class="menu-item" @click="goToEditing">个人资料</view>
<view class="menu-item">列表</view>
</view>
</view>
</template>
<style scoped>
.popup-content {
padding: 20px;
background-color: #fff;
height: 100%;
}
.profile-section {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.profile-image {
width: 50px;
height: 50px;
border-radius: 50%;
}
.profile-name {
font-size: 18px;
font-weight: bold;
margin-left: 10px;
}
.profile-username {
font-size: 14px;
color: #888;
margin-left: 10px;
}
.profile-stats {
margin-bottom: 20px;
}
.menu-items {
display: flex;
flex-direction: column;
}
.menu-item {
padding: 10px 0;
border-bottom: 1px solid #eee;
cursor: pointer;
}
</style>
EditingInformation
<script setup>
import { ref } from 'vue'
const avatar = ref('/static/logo.png') // 默认头像路径
const name = ref('')
const bio = ref('')
const location = ref('')
const website = ref('')
const birthdate = ref('')
// 返回上一页
const goBack = () => {
uni.navigateBack()
}
// 保存资料
const saveProfile = () => {
console.log('保存资料', {
name: name.value,
bio: bio.value,
location: location.value,
website: website.value,
birthdate: birthdate.value,
})
// 保存逻辑
}
// 选择头像图片
const chooseAvatarImage = () => {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
avatar.value = res.tempFilePaths[0]
},
})
}
// 选择背景图片
const chooseBackgroundImage = () => {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
console.log('选择的背景图片', res.tempFilePaths)
},
})
}
</script>
<template>
<div class="profile-edit-container">
<div class="navbar">
<div class="navbar-back" @click="goBack">返回</div>
<div class="navbar-title">编辑个人资料</div>
<div class="navbar-save" @click="saveProfile">保存</div>
</div>
<div class="header">
<div class="background-image">
<div class="change-bg-icon" @click="chooseBackgroundImage">选择图片</div>
</div>
<div class="profile-info">
<img class="avatar" :src="avatar" alt="头像" @click="chooseAvatarImage" />
</div>
</div>
<div class="user-details">
<div class="user-detail-item">
<label>姓名</label>
<input type="text" v-model="name" />
</div>
<div class="user-detail-item">
<label>简介</label>
<input type="text" v-model="bio" />
</div>
<div class="user-detail-item">
<label>位置</label>
<input type="text" v-model="location" />
</div>
<div class="user-detail-item">
<label>加入时间</label>
<input type="text" v-model="website" />
</div>
<div class="user-detail-item">
<label>出生日期</label>
<input type="date" v-model="birthdate" />
</div>
</div>
</div>
</template>
<style scoped>
.profile-edit-container {
width: 100%;
font-family: Arial, sans-serif;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
margin-top: 2rem; /* 添加顶部外边距,适配不同手机 */
background-color: #fff;
}
.navbar-back,
.navbar-save {
cursor: pointer;
color: #1da1f2;
}
.navbar-title {
font-weight: bold;
font-size: 1.2rem; /* 调整字体大小 */
}
.header {
position: relative;
width: 100%;
height: 20vh;
background-color: #1da1f2;
}
.background-image {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #1da1f2;
}
.change-bg-icon {
color: white;
font-size: 2rem;
cursor: pointer;
}
.profile-info {
position: absolute;
bottom: -5vh;
left: 2vw;
display: flex;
align-items: center;
}
.avatar {
width: 16vw;
height: 16vw;
border-radius: 50%;
border: 0.5vw solid white;
cursor: pointer;
}
.user-details {
margin-top: 10vh;
padding: 0 2vw;
}
.user-detail-item {
margin-bottom: 1.2rem;
}
.user-detail-item label {
display: block;
color: #999; /* 淡化处理 */
margin-bottom: 0.5rem;
font-size: 0.8rem; /* 调整字体大小 */
}
.user-detail-item input {
width: 100%;
padding: 0.5rem;
font-size: 1rem; /* 调整字体大小 */
border: none; /* 去除边框 */
border-bottom: 0.1rem solid #ccc; /* 只保留底部边框 */
border-radius: 0; /* 去除边框圆角 */
}
/* 使用媒体查询适配不同设备 */
@media (min-width: 768px) {
.navbar {
margin-top: 3rem; /* 平板设备上增加更大的顶部外边距 */
}
}
@media (min-width: 1024px) {
.navbar {
margin-top: 4rem; /* 桌面设备上增加更大的顶部外边距 */
}
}
</style>
profile
<script setup lang="ts">
import { ref } from 'vue'
const selectedTab = ref('帖子')
const selectTab = (tab: string) => {
selectedTab.value = tab
}
const goToEditing = () => {
// 使用uniapp的导航方法跳转到指定页面
uni.navigateTo({
url: '/components/HeadPortrait/EditingInformation',
})
}
const goBack = () => {
uni.navigateBack()
}
</script>
<template>
<div class="profile-container">
<div class="header">
<div class="navbar-back" @click="goBack">返回</div>
<div class="background-image"></div>
<div class="profile-info">
<img class="avatar" src="/static/logo.png" alt="头像" />
<div class="edit-button" @click="goToEditing">编辑个人资料</div>
</div>
</div>
<div class="user-details">
<h2>Qiuner</h2>
<!-- <p>@wsjw3635</p> -->
<p>出生于 2004年3月15日 | 2023年1月 加入</p>
<p>3 正在关注 | 0 关注者</p>
</div>
<div class="tabs">
<div class="tab" :class="{ active: selectedTab === '帖子' }" @click="selectTab('帖子')">
帖子
</div>
<div class="tab" :class="{ active: selectedTab === '回复' }" @click="selectTab('回复')">
回复
</div>
<div class="tab" :class="{ active: selectedTab === '媒体' }" @click="selectTab('媒体')">
媒体
</div>
<div class="tab" :class="{ active: selectedTab === '喜欢' }" @click="selectTab('喜欢')">
喜欢
</div>
</div>
</div>
</template>
<style scoped>
.profile-container {
width: 100%;
font-family: Arial, sans-serif;
}
.header {
position: relative;
width: 100%;
height: 20vh;
background-color: #1da1f2;
}
.navbar-back {
position: absolute;
top: 10px;
left: 10px;
font-size: 1.5rem;
color: white;
cursor: pointer;
padding: 0.5rem;
z-index: 10; /* 确保按钮在最上层 */
}
.background-image {
position: absolute;
width: 100%;
height: 100%;
background-size: cover;
}
.profile-info {
position: absolute;
bottom: -5vh;
left: 2vw;
display: flex;
align-items: center;
width: 100%;
padding-right: 2vw;
}
.avatar {
width: 16vw;
height: 16vw;
border-radius: 50%;
border: 0.5vw solid white;
}
.edit-button {
margin-left: auto;
margin-right: 2vw;
padding: 0.5rem 1rem;
background-color: white;
border: 0.1rem solid #ccc;
border-radius: 2rem;
cursor: pointer;
}
.user-details {
margin-top: 8vh;
padding: 0 2vw;
}
.user-details h2 {
margin: 0;
font-size: 2rem;
}
.user-details p {
margin: 0.5rem 0;
color: #555;
}
.tabs {
display: flex;
justify-content: space-around;
margin-top: 2rem;
border-top: 0.1rem solid #ccc;
}
.tab {
padding: 1rem 0;
cursor: pointer;
font-weight: bold;
}
.tab.active {
color: #1da1f2;
border-bottom: 0.2rem solid #1da1f2;
}
.tab:hover {
color: #1da1f2;
}
</style>
到目前为止项目结构图
- 注意 看到没有的不要惊讶 因为我这是做了后面内容回来检查前面博客写得怎么样,因此只需要检查已有的文件位置是不是对的
pages.json文件
- 直接复制会报错哦,因为有没有的东西。小伙伴们可以自己尝试一下怎么修复能不报错
{
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/message/message",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "message"
}
},
{
"path": "pages/organization/organization",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "organization"
}
},
{
"path": "pages/test/test",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "test"
}
},
{
"path": "pages/writing/writing",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "writing"
}
},
{
"path": "components/HeadPortrait/profile",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "profile"
}
},
{
"path": "components/HeadPortrait/EditingInformation",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "EditingInformation"
}
},
{
"path": "pages/organization/components/OrganizationDetails",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "OrganizationDetails"
}
},
{
"path": "components/Post/Post",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "Post"
}
},
{
"path": "components/Post/PostDetails",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "PostDetails"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#333333",
"selectedColor": "#333333",
"backgroundColor": "#ffffff",
"borderStyle": "white",
"list": [
{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home.png"
},
{
"text": "组织",
"pagePath": "pages/organization/organization",
"iconPath": "static/tabbar/organization.png",
"selectedIconPath": "static/tabbar/organization.png"
},
{
"text": "消息",
"pagePath": "pages/message/message",
"iconPath": "static/tabbar/message.png",
"selectedIconPath": "static/tabbar/message.png"
},
{
"text": "test",
"pagePath": "pages/test/test",
"iconPath": "static/logo.png",
"selectedIconPath": "static/logo.png"
}
]
}
}
你好,我是Qiuner. 为帮助别人少走弯路而写博客 这是我的 github https://github.com/Qiuner⭐ gitee https://gitee.com/Qiuner 🌹
如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 😄 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。
代码都在github或gitee上,如有需要可以去上面自行下载。记得给我点星星哦😍
如果你遇到了问题,自己没法解决,可以去我掘金评论区问。私信看不完,CSDN评论区可能会漏看 掘金账号 https://juejin.cn/user/1942157160101860 掘金账号
更多专栏:感谢订阅专栏 三连文章
更多推荐
已为社区贡献6条内容
所有评论(0)