我的头条(vue项目实战)--个人中心页

个人中心页的效果如上所示。我们分析一下应该如何实现这样的布局。首先蓝色背景色的是一个大的div,然后头像和用户信息也是一个div包裹,下面的动态粉丝关注则是需要三个div,这样个人信息框大致布局就完成了。下面的只需要三个input输入框就可以解决了,这样个人中心页布局就完成了。

<template>
  <div class="user-container">
    <!-- 用户基本信息面板 -->
    <div class="user-card" >
      <!-- 用户头像、姓名 -->
      <van-cell >
        <!-- 使用 title 插槽来自定义标题 -->
        <template #icon>
          <img :src="list.photo" alt="" class="avatar">
        </template>
        <template #title>
          <span class="username">{{list.name}}</span>
        </template>
        <template #label>
          <van-tag color="#fff" text-color="#007bff">申请认证</van-tag>
        </template>
      </van-cell>
      <!-- 动态、关注、粉丝 -->
      <div class="user-data">
        <div class="user-data-item">
          <span>{{list.art_count}}</span>
          <span>动态</span>
        </div>
        <div class="user-data-item">
          <span>{{list.follow_count}}</span>
          <span>关注</span>
        </div>
        <div class="user-data-item">
          <span>{{list.fans_count}}</span>
          <span>粉丝</span>
        </div>
      </div>
    </div>

    <!-- 操作面板 -->
    <van-cell-group class="action-card">
      <van-cell icon="edit" title="编辑资料" is-link @click="edit"/>
      <van-cell icon="chat-o" title="小思同学" is-link />
      <van-cell icon="warning-o" title="退出登录" is-link @click="logout"/>
    </van-cell-group>
  </div>
</template>

<script>
import { UserAPI } from '@/api'
import Vue from 'vue'
import { Dialog } from 'vant'
import { removeToken } from '@/utils/token'
Vue.use(Dialog)
export default {
  async created () {
    const res1 = await UserAPI()
    console.log(res1)
    this.list = res1.data.data
    console.log(this.list)
  },
  data () {
    return {
      list: {}
    }
  },
  methods: {
    logout () {
      Dialog.confirm({
        title: '退出登录',
        message: '退出后本网站不保存你的当前操作,真的要退出吗'
      })
        .then(() => {
        // on confirm
          removeToken()
          this.$router.replace('/login')
        })
        .catch(() => {
        // on cancel
        })
    },
    edit () {
      this.$router.push('/userEdit')
    }
  }
}
</script>

<style scoped lang="less">
.user-container {
  .user-card {
    background-color: #007bff;
    color: white;
    padding-top: 20px;
    .van-cell {
      background: #007bff;
      color: white;
      &::after {
        display: none;
      }
      .avatar {
        width: 60px;
        height: 60px;
        background-color: #fff;
        border-radius: 50%;
        margin-right: 10px;
      }
      .username {
        font-size: 14px;
        font-weight: bold;
      }
    }
  }
  .user-data {
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    font-size: 14px;
    padding: 30px 0;
    .user-data-item {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 33.33%;
    }
  }
}
</style>

 页面布局已完成。

<template>
  <div class="user-edit-container">
    <!-- Header 区域 -->
    <van-nav-bar title="编辑资料" left-arrow @click-left="$router.back()" fixed />

    <!-- 用户资料 -->
    <van-cell-group class="action-card">
      <van-cell title="头像" is-link center>
        <template #default>
          <van-image round class="avatar" :src="list.photo" @click="Click"/>
          <input
          type="file"
          ref="iptFile"
          v-show="false"
          accept="image/*"
          @change="onFileChange"
          />
        </template>
      </van-cell>
      <van-cell title="名称" is-link  :value="list.name" @click="nameClick"/>
      <van-cell title="生日" is-link  :value="list.birthday" @click="birthdayClick"/>
    </van-cell-group>
    <!-- 修改姓名的组件 组件调用方式-->
<van-dialog v-model="show" title="修改用户名" show-cancel-button :before-close="beforeClose">
  <input v-haha type="text" v-model="username"/>
</van-dialog>
<!-- 时间选择器 -->
<van-popup round="true"  v-model="dateShow" position="bottom" :style="{height: '50%'}">
<van-datetime-picker
  v-model="currentDate"
  type="date"
  title="选择年月日"
  :min-date="minDate"
  :max-date="maxDate"
  @cancel="dateCancel"
  @confirm ="confirmDate"
/>
</van-popup>
  </div>
</template>

<script>
import { Image, Notify, DatetimePicker, Popup } from 'vant'
import Vue from 'vue'
import { updatePhotoAPI, updateUserInfo, userInfoAPI } from '@/api'
import { formatDate } from '../../utils/date'
Vue.use(Image)
Vue.use(Notify)
Vue.use(DatetimePicker)
Vue.use(Popup)
export default {
  name: 'UserEdit',
  data () {
    return {
      list: {},
      show: false, // 控制对话框的显示与隐藏
      username: '',
      minDate: new Date(1970, 0, 1),
      maxDate: new Date(2025, 11, 31),
      currentDate: new Date(2022, 7, 24),
      dateShow: false
    }
  },
  async created () {
    const res = await userInfoAPI()
    console.log(res)
    this.list = res.data.data
    console.log(this.list)
  },
  methods: {
    // 文件改变事件
    async onFileChange (e) {
      if (e.target.files.length === 0) return // 如果没有数据直接返回
      console.log(e.target.files[0])
      const theFd = new FormData()
      theFd.append('photo', e.target.files[0])
      const res = await updatePhotoAPI(theFd)
      console.log(res)
      this.item.photo = res.data.data.photo
    },
    // 头像点击事件
    Click () {
      this.$refs.iptFile.click() // JS模拟标签事件触发
    },
    // 名称改变事件
    async nameClick () {
      this.show = true
      this.username = this.list.name
    },
    // 姓名修改框关闭前的回调
    async beforeClose (action, done) {
      if (action === 'confirm') {
        // 点击确定
        const reg = /^[a-zA-Z0-9\u4e00-\u9fa5]{1,7}$/
        if (reg.test(this.username) === true) {
          // 通过了校验,关闭弹窗
          await updateUserInfo({
            name: this.username
          })
          this.list.name = this.username
          done()
        } else {
          Notify({ type: 'warning', message: '用户名只能是1-7位中英文数字组合' })
          done(false)
        }
      } else {
        done() // 关闭修改框
      }
    },
    // 生日修改事件
    async birthdayClick () {
      this.dateShow = true
      this.currentDate = new Date(this.list.birthday)
    },
    // 日期选择器取消
    dateCancel () {
      this.dateShow = false
    },
    async  confirmDate () {
      await updateUserInfo({
        birthday: formatDate(this.currentDate)
      })
      this.list.birthday = formatDate(this.currentDate)
      this.dateShow = false
    }
  }
}
</script>

<style lang="less" scoped>
.user-edit-container {
  padding-top: 1.2432rem;
  .avatar {
    width: 1.3514rem;
    height: 1.3514rem;
  }
}
/deep/.van-dialog__content{
  text-align: center;
  input{
    padding:0;
    outline: none;
    border:none;
    text-align: center;
  }
}
/deep/.van-dialog{
  height:3.6667rem;
}
</style>

 修改用户信息也完成。

发送的接口请求:

// 获取用户个人资料

export const userInfoAPI = () => request({

  url: '/v1_0/user/profile'

})

// 获取用户自己信息

export const UserAPI = () => request({

  url: '/v1_0/user'

})

// 更改用户头像

export const updatePhotoAPI = (fd) => request({

  url: '/v1_0/user/photo',

  method: 'PATCH',

  data: fd // 外面一会传进来的新表单数据,切记不能写对象,不然axios会解析成json文件

})

// 编辑用户个人资料

export const updateUserInfo = (obj) => {

  return request({

    url: '/v1_0/user/profile',

    method: 'PATCH',

    data: obj // data不会忽略值为null的那对键值对,params遇到null值会忽略不携带此键值对给后台obj

  })

}

由于小思同学需要用到websocket技术,还没学会所以暂时没实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zwq8023520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值