Vue博客搭建(17)个人中心3

404 阅读2分钟

在上一篇文章中,我们做好了头像的后端读取,下面就要进行的是前端对于文件的发送,以及个人中心的资料设定等内容。

前端上传文件

前端上传的时候要选择http请求头类型为multipart/form-data,需要在axios请求发送的时候配置。

<script setup>
import axios from 'axios'

import {useUserAccountStore} from '../stores/userAccount'

const userAccountStore = useUserAccountStore();

function upload(event){
    const file = event.target.files[0];
    console.log(file);
    axios.post('/server/uploadAvatar',{
        avatar: file,
        id: userAccountStore.id,
    },{
        headers: {'Content-Type':'multipart/form-data'}
    })
    .then((response)=>{
        alert('上传头像成功');
    })
    .catch((err)=>{
        alert(`上传头像失败,${err}`);
    })
}

</script>

<template>
    <div>
        上传头像
        <img>
        <input type="file" @change="upload"/>
    </div>

</template>

<style scoped>
</style>

组件库的安装与使用

为了使用个人中心的编辑生日功能,我们需要一个组件用来选择日期。这种组件写起来既麻烦又难写,对于我们这种比较初级的项目来说,便可以借助别人已经写好的组件库来进行使用。这里我们选择饿了么前端团队推出的element-plus

由于我们不需要整个组件库,而是只需要其中的一个或者几个组件,因此我们先来学习按需导入。按需导入使用的是一种叫做Tree Shaking的技术,借助unplugin-element-plusunplugin-auto-import包。

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'


// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    })
  ]
  // ... 
})

接下来当我们想使用对应的组件的时候即可直接按需导入。

            <h3>出生日期</h3>
            <div><el-date-picker></el-date-picker></div>

现在在个人空间里就可以选择自己的出生日期了。

axios的二次封装

在个人信息的前端获取中,我们需要一个方法来获取个人信息,并且对于所有的用户ID,我们需要一个通用的方法来去后端获取。因此我们需要把axios封装成一个新的函数。这里以get方法为例介绍一下axios的二次封装。

function getUserInformationById(id){
        return new Promise((resolve, reject)=>{
            axios.get(`/server/getInformation/${id}`)
            .then((response)=>{
                resolve (response.data)
            })
        })
    }

如果想查看其他的封装,可以看下文的完整实现。

个人资料的编辑和保存

接下来我们就可以实现个人资料的编辑和保存了。大致思路是这样的:主页中有个按钮用来控制当前的状态isEditing,然后组件根据状态变量来显示是保存还是编辑(除了头像之外),然后旁边会附带一个保存按钮,用来把更新后的数据上传。

思路弄好了之后就直接展示最终的代码好了。

这是前端代码:

<script setup>
import { ref } from 'vue';
import uploadAvatar from './uploadAvatar.vue';
import {useUserAccountStore} from '../stores/userAccount'
import { useUserInformationStore } from '../stores/userInformation';
import axios from 'axios';

const userAccountStore = useUserAccountStore();
const userInformationStore = useUserInformationStore();

const uploadAvaterIsOn = ref(false);
const isEditing = ref(false);
const userInformationInput = ref({
    id: userAccountStore.id,
    username: '',
    birthday: '',
    avatar: '',
    profileText: '',
})

function updateInformation(){
    userInformationStore.updateInformation(userInformationInput.value)
    .then((val)=>{
        isEditing.value = !isEditing.value;
        alert(val);
    })
}

userInformationStore.getUserInformationById(userAccountStore.id).then((val)=>{
    const url = `server/files/avatars/${val.avatar}`;
    userInformationInput.value = val;
    userInformationInput.value.avatar = url;
})
</script>

<template>
基本信息
    <div>
        <button v-if="!isEditing" @click="isEditing = !isEditing">编辑</button>
        <div v-else>
            <button @click="updateInformation">保存</button>
            <button @click="isEditing = !isEditing">取消</button>
        </div>
        <ul>
        <li>
            <h3 >头像</h3>
            <img :src="userInformationInput.avatar" 
            @click="uploadAvaterIsOn = !uploadAvaterIsOn"  id="avatar"/>
        </li>
        <li>
            <h3>用户名</h3>
            <div v-if="!isEditing">{{ userInformationInput.username }}</div>
            <input v-model="userInformationInput.username" v-else/>
        </li>
        <li>
            <h3>用户id</h3>
            <div>{{ userInformationInput.id }}</div>
        </li>
        <li>
            <h3>注册邮箱</h3>
            <div>{{  }}</div>
        </li>
        <li>
            <h3>出生日期</h3>
            <div v-if="!isEditing" >{{ userInformationInput.birthday }}</div>
            <div v-else>
                <el-date-picker v-model="userInformationInput.birthday"
                value-format="YYYY-MM-DD">
                </el-date-picker>
            </div>
        </li>
        <li>
            <h3>签名</h3>
            <div v-if="!isEditing">{{  userInformationInput.profileText }}</div>
            <div v-else><input v-model="userInformationInput.profileText"></div>
        </li>
    </ul>
    </div>
</template>

<style scoped>
#avatar{
    height: 200px;
    width: 200px;
}
</style>

以及配套的userInformationStore的代码:

import axios from "axios";
import { defineStore } from "pinia";

export const useUserInformationStore = defineStore('userInformation',()=>{
    function getUserInformationById(id){
        return new Promise((resolve, reject)=>{
            axios.get(`/server/getInformation/${id}`)
            .then((response)=>{
                resolve(response.data);
            })
        })
    }
    function updateInformation(information){
        return new Promise((resolve, reject)=>{
            axios.post('/server/updateInformation',information)
            .then((response)=>{
                resolve(response.data);
            })
            .catch((err)=>{
                reject(err);
            })
        })
    }
    return{
        getUserInformationById,
        updateInformation
    }
})

对应的后端代码如下:

// getInformation.js
const express = require('express');
const router = express.Router();
const connection = require('../funcitons/sqlConnection');

router.get('/getInformation/:id',(req, res)=>{
    const id = req.params.id;
    const sql = `select * from userInformation where id = '${id}'`;
    connection.query(sql,(err, result)=>{
        if(err){
            res.status(500).send(err);
        }else{
            res.send(result[0]);
        }
    })
})
module.exports = router;

// updateInformation.js
const express = require('express');
const router = express.Router();
const connection = require('../funcitons/sqlConnection');

router.post('/updateInformation',(req, res)=>{
    const information ={
        username: req.body.username,
        birthday: req.body.birthday,
        profileText: req.body.profileText
    };
    const sql = `
        update userInformation set username = '${information.username}', 
        birthday = '${information.birthday}', profileText = '${information.profileText}'
        where id = '${req.body.id}'
    `;
    connection.query(sql, (err, result)=>{
        if(err){
            res.status(500).send(err);
        }else{
            res.send('更新完成');
        }
    });
});

module.exports = router;

在接下来的文章中,我们在搭建完个人中心后,便会着重处理页面外观,包括响应式、ui设计以及组件美化等。