Home  >  Article  >  Web Front-end  >  How to select an avatar and crop it in Vue3

How to select an avatar and crop it in Vue3

WBOY
WBOYforward
2023-05-29 10:22:491337browse

Final effect

How to select an avatar and crop it in Vue3

Install VueCropper component

yarn add vue-cropper@next

The above installation value is for Vue3. If it is Vue2 or you want to use other methods to reference, please Visit its official npm address: official tutorial.

Referencing in components

It is also very simple to use. You only need to introduce the corresponding component and its style file. I do not reference it globally here, only introduce it in my component file

<script>
import { userInfoByRequest } from &#39;../js/api&#39;
import { VueCropper } from &#39;vue-cropper&#39;
import &#39;vue-cropper/dist/index.css&#39;
export default {
    components: {
        VueCropper
    },
}

Then use the <vue-cropper></vue-cropper> tag to use it. It should be noted that it needs to be wrapped by an outer container and set a specified height for the outer container.

<el-dialog title="头像设置" v-model="showSetAvatarDialog">
            <div class="cropperBox">
                <vue-cropper ref="cropper" :canMoveBox="false" :img="avatarBase64" :fixedBox="true" :autoCrop="true"
                    autoCropWidth="200" autoCropHeight="200" outputType="png"></vue-cropper>
            </div>
            <div class="optionBtn">
                <el-button @click="rotateLeft"><i class="fa fa-rotate-left"></i>左旋转</el-button>
                <el-button @click="rotateRight"><i class="fa fa-rotate-right"></i>右旋转</el-button>
                <el-button @click="getPickAvatar" type="primary"><i class="fa fa-save"></i>保存</el-button>
            </div>
</el-dialog>

Here I put it in a Dialog pop-up box. This pop-up box will pop up after selecting the picture.
For some of its properties, please refer to: Detailed description in the official tutorial. The meaning of the properties used above:

  • canMoveBox: Whether the screenshot box can be moved, the default is yes, I set it to false because I want the image to move and the screenshot box not to move.

  • img: Image source, which can be an image URL or base64 data.

  • fixedBox: It is not allowed to change the size of the screenshot box. It is allowed by default. Here I set it to true because I want a square with fixed length and width.

  • autoCrop: Whether to generate a screenshot box by default, set to true here

  • autoCropWidth: Automatically generate the default width of the screenshot box

  • autoCropHeight: The default height of the automatically generated screenshot frame

  • outputType: The format of the output image, here I set it to png format

Get the content of the image

Use the following method to get the content of the intercepted image using its built-in method

//获取base64格式的截图内容
this.$refs.cropper.getCropData(data => {
  // do something
  console.log(data)  
})
//获取blob格式的截图内容
this.$refs.cropper.getCropBlob(data => {
  // do something
  console.log(data)  
})

For more other built-in methods, please refer to the detailed description in the official tutorial.

Customize uploaded pictures

The screenshot component is now available. Now we need to select an image, and then convert it to base64 through the front end and pop up the screenshot component for selection. Here we use the native input tag, type is file, but the native style is not what we want. In the demonstration, I clicked on a small camera icon and then selected the picture. The implementation process is as follows:

  1. First add the hidden attribute to , hide it

  2. Then when the camera icon is clicked, the event of clicking the input is implemented through js

  3. Define the change event in the input tag, proceed The logic of converting images to base64

  4. Then set the converted data to global variables

Complete code implementation

UserCenter .vue

<template>
    <div class="userCenter">
        <input id="avatarFile" type="file" hidden @change="selectFile" />
        <header>
            <div class="avatar">
                <div class="back">
                    <el-tooltip content="返回">
                        <i @click="back" class="fa fa-arrow-left"></i>
                    </el-tooltip>
                </div>
                <div class="topInfo">
                    <el-avatar :size="120" :src="avatarBlob==null?(userInfo.avatar==null?defaultAvatar:userInfo.avatar):avatarBlob"></el-avatar>
                    <div class="setAvatar">
                        <el-tooltip content="修改头像">
                            <i @click="getFile" class="fa fa-camera"></i>
                        </el-tooltip>
                    </div>
                    <div class="username">{{userInfo.nickName}}</div>
                </div>
            </div>
        </header>
        <el-row justify="center">
            <el-col :lg="12" :xl="12" :md="18" :sm="20" :xs="20">
                <div class="userInfoBox">
                    <div class="headerOption">
                        <el-tooltip content="修改用户基本信息,涉及账号的修改请点击底栏的操作按钮">
                            <el-link @click="editUserInfo"><i class="fa fa-edit"></i></el-link>
                        </el-tooltip>
                    </div>
                    <ul>
                        <li>
                            <div class="userInfoTitle">用户名:</div>
                            <div class="userInfoValue">{{userInfo.username}}</div>
                        </li>
                        <li>
                            <div class="userInfoTitle">邮箱:</div>
                            <div class="userInfoValue">{{userInfo.email}}</div>
                        </li>
                        <li>
                            <div class="userInfoTitle">昵称:</div>
                            <div class="userInfoValue">{{userInfo.nickName}}</div>
                        </li>
                        <li>
                            <div class="userInfoTitle">性别:</div>
                            <div class="userInfoValue">{{userInfo.gender==3?&#39;保密&#39;:(userInfo.gender==0?&#39;男&#39;:&#39;女&#39;)}}</div>
                        </li>
                        <li>
                            <div class="userInfoTitle">年龄:</div>
                            <div class="userInfoValue">{{userInfo.age}}</div>
                        </li>
                        <li>
                            <div class="userInfoTitle">生日:</div>
                            <div class="userInfoValue">{{userInfo.birthday}}</div>
                        </li>
                    </ul>
                </div>
            </el-col>
        </el-row>
        <div class="option">
            <el-button class="optionBtn" size="large" round><i class="fa fa-user"></i>用户名修改</el-button>
            <el-button class="optionBtn" size="large" round><i class="fa fa-lock"></i>修改密码</el-button>
            <el-button class="optionBtn" size="large" round><i class="fa fa-envelope"></i>修改邮箱</el-button>
            <el-button class="optionBtn" size="large" round><i class="fa fa-toggle-on"></i>激活邮箱</el-button>
            <el-button class="optionBtn" size="large" round><i class="fa fa-power-off"></i>注销账号</el-button>
        </div>
        <el-dialog title="基本信息" v-model="showUserInfoDialog">
            <el-form :model="userInfoForm">
                <el-form-item label="昵称">
                    <el-input placeholder="请输入昵称" v-model="userInfoForm.nickName"></el-input>
                </el-form-item>
                <el-form-item label="性别">
                    <el-select v-model="userInfoForm.gender">
                        <el-option v-for="item in genders" :key="item.id" :label="item.genderName"
                            :value="item.genderCode"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="生日">
                    <el-date-picker v-model="userInfoForm.birthday" :locale="locale" placeholder="选择出生日期"
                        value-format="yyyy-MM-dd"></el-date-picker>
                </el-form-item>
                <div class="submitBtn" >
                    <el-button @click="showUserInfoDialog=false" type="info">取消</el-button>
                    <el-button type="primary">确定</el-button>
                </div>
            </el-form>
        </el-dialog>
        <el-dialog title="头像设置" v-model="showSetAvatarDialog">
            <div class="cropperBox">
                <vue-cropper ref="cropper" :canMoveBox="false" :img="avatarBase64" :fixedBox="true" :autoCrop="true"
                    autoCropWidth="200" autoCropHeight="200" outputType="png"></vue-cropper>
            </div>
            <div class="optionBtn">
                <el-button @click="rotateLeft"><i class="fa fa-rotate-left"></i>左旋转</el-button>
                <el-button @click="rotateRight"><i class="fa fa-rotate-right"></i>右旋转</el-button>
                <el-button @click="getPickAvatar" type="primary"><i class="fa fa-save"></i>保存</el-button>
            </div>
        </el-dialog>
    </div>
</template>
<script>
import { userInfoByRequest } from &#39;../js/api&#39;
import { VueCropper } from &#39;vue-cropper&#39;
import &#39;vue-cropper/dist/index.css&#39;
export default {
    components: {
        VueCropper
    },
    data() {
        return {
            userInfo: {},
            defaultAvatar: &#39;https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png&#39;,
            userInfoForm: {},
            genders: [
                {
                    id: 1,
                    genderName: &#39;男性&#39;,
                    genderCode: 0,
                },
                {
                    id: 2,
                    genderName: &#39;女性&#39;,
                    genderCode: 1,
                },
                {
                    id: 3,
                    genderName: &#39;保密&#39;,
                    genderCode: 3,
                }
            ],
            showUserInfoDialog: false,
            showSetAvatarDialog: false,
            avatarBase64:&#39;&#39;,
            avatarBlob: null
        }
    },
    methods: {
        back() {
            this.$router.go(-1)
        },
        getUserInfo() {
            userInfoByRequest().then(res => {
                this.userInfo = res.data;
            })
        },
        editUserInfo() {
            this.userInfoForm.nickName = this.userInfo.nickName;
            this.userInfoForm.gender = this.userInfo.gender;
            this.userInfoForm.birthday = this.userInfo.birthday;
            this.showUserInfoDialog = true;
        },
        getPickAvatar() {
            this.$refs.cropper.getCropData(data => {
                this.avatarBlob = data
            })
            this.showSetAvatarDialog = false;
        },
        rotateLeft() {
            this.$refs.cropper.rotateLeft();
        },
        rotateRight() {
            this.$refs.cropper.rotateRight();
        },
        getFile() {
            let fileEle = document.getElementById(&#39;avatarFile&#39;)
            fileEle.click()
        },
        selectFile(e) {
            var file = e.target.files[0];
            var filesize = file.size;
            var filename = file.name;
            var reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = (e) => {
                var imgcode = e.target.result;
                this.avatarBase64 = imgcode
                this.showSetAvatarDialog = true;
            }
        }
    },
    mounted() {
        this.getUserInfo();
    }
}
</script>
<style scoped>
.userCenter {
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.username {
    color: #fff;
    font-weight: bold;
    font-size: 19px;
    padding: 0 10px;
}

header {
    text-align: center;
    padding: 10px;
    background-color: #333;

}

.topInfo {
    animation: userInfoCard 2s;
    -webkit-animation: userInfoCard 2s;
    /* Safari and Chrome */
}

.back {
    text-align: left;
    color: #fff;
    position: relative;
    left: 10px;
}

.back>i {
    cursor: pointer;
}

.userInfoBox {
    box-shadow: 2px 3px 10px #D3d7d4;
    margin-top: 20px;
    padding: 20px;
    background-color: #fff;
    font-size: 16px;
    text-align: center;
    border-radius: 4px;
    animation: userInfoCard 3s;
    -webkit-animation: userInfoCard 3s;
    /* Safari and Chrome */
}

.setAvatar {
    position: relative;
    top: -20px;
    font-size: 14px;
    color: #000;
    margin: -10px;
}

.setAvatar>i {
    cursor: pointer;
}

ul>li {
    display: flex;
    padding: 5px;
}

.userInfoTitle {
    font-weight: bold;
    width: 100px;
    text-align: right;
    padding-right: 10px;
}

.option {
    width: 100%;
    text-align: center;
    position: fixed;
    bottom: 20px;
    border: 1px solid gainsboro;
    padding: 10px;
}

.optionBtn {
    font-weight: bold;
    text-align: center;
    margin-top: 10px;
}

.headerOption {
    text-align: right;
}

@keyframes userInfoCard {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@-webkit-keyframes userInfoCard

/* Safari and Chrome */
    {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

.cropperBox {
    width: 100%;
    height: 300px;
}
</style>

The above is the detailed content of How to select an avatar and crop it in Vue3. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete