nuxt实现图片裁剪


<template>
  <div :class="$options.name">
    <div class="icon-img">
      <img :src="previewsUrl || ''" class="img" v-default="'avatar'" />
    </div>
    <div class="middle">
      <div class="button" @click="showModal">头像编辑</div>
    </div>
    <div class="bottom">请选择JPG、PNG格式,小于2M的图片</div>
    <a-modal
      v-model="visible"
      :maskClosable="false"
      title="头像编辑"
      :footer="null"
      dialogClass="cut-pic"
    >
      <i class="close-icon lkrfont icon-dacha" slot="closeIcon"></i>
      <div class="content">
        <div class="left">
          <div class="cropper-content">
            <div class="cropper" style="text-align: center">
              <component
                v-bind:is="cropper"
                ref="cropper"
                :img="option.img"
                :outputSize="option.size"
                :outputType="option.outputType"
                :info="true"
                :full="option.full"
                :canMove="option.canMove"
                :canMoveBox="option.canMoveBox"
                :original="option.original"
                :autoCrop="option.autoCrop"
                :fixed="option.fixed"
                :fixedNumber="option.fixedNumber"
                :centerBox="option.centerBox"
                :infoTrue="option.infoTrue"
                :fixedBox="option.fixedBox"
                @realTime="realTime"
              ></component>
            </div>
          </div>
        </div>

        <div class="right">
          <div class="text text1">100px × 100px</div>
          <div class="text text2">50px × 50px</div>
          <div class="text text3">30px × 30px</div>
          <div class="child">
            <div class="show-preview1">
              <div :style="previews.div" class="preview">
                <img :src="previews.url" :style="previews.img" />
              </div>
            </div>
          </div>
          <div class="child">
            <div class="show-preview2">
              <div :style="previews.div" class="preview">
                <img :src="previews.url" :style="previews.img" />
              </div>
            </div>
          </div>
          <div class="child">
            <div class="show-preview3">
              <div :style="previews.div" class="preview">
                <img :src="previews.url" :style="previews.img" />
              </div>
            </div>
          </div>
        </div>
      </div>
      <label class="btn" for="uploads">{{
        option.img ? "重新上传" : "上传图片"
      }}</label>

      <input
        type="file"
        id="uploads"
        style="position: absolute; clip: rect(0 0 0 0); display: none"
        accept="image/png, image/jpeg, image/gif, image/jpg"
        ref="image"
        @change="selectImg($event)"
      />
      <div class="footer">
        <div class="cancel" @click="visible = false">取 消</div>
        <div class="submit" type="primary" @click="finish" :loading="loading">
          确认
        </div>
      </div>
    </a-modal>
  </div>
</template>

<script>
import axios from "axios";
import Vue from "vue";
import $utils from "@/plugins/utils";
export default {
  name: "HeadEdit",
  props: {
    initAvatarUrl: {
      type: String,
      default: "",
    },
  },
  mounted() {
    const res = require("vue-cropper");
    Vue.component("VueCropper", res.VueCropper);
    this.cropper = "vue-cropper";
  },
  data() {
    return {
      visible: false,
      cropper: "",
      previews: {},
      previewsUrl: this.initAvatarUrl,
      // 裁剪组件的基础配置option
      option: {
        img: "", // 裁剪图片的地址
        info: true, // 裁剪框的大小信息
        outputSize: 1, // 裁剪生成图片的质量
        outputType: "jpeg", // 裁剪生成图片的格式
        canScale: false, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        autoCropWidth: 100, // 默认生成截图框宽度
        autoCropHeight: 100, // 默认生成截图框高度
        fixedBox: true, // 固定截图框大小 不允许改变
        fixed: true, // 是否开启截图框宽高固定比例
        fixedNumber: [1, 1], // 截图框的宽高比例
        full: true, // 是否输出原图比例的截图
        canMoveBox: false, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: false, // 截图框是否被限制在图片里面
        infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
      },
      // 防止重复提交
      loading: false,
    };
  },

  methods: {
    showModal() {
      this.visible = true;
    },
    //选择图片
    selectImg(e) {
      let file = e.target.files[0];
      this.fileName = file.name;
      if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
        this.$message.error("图片类型要求:jpeg、jpg、png");
        return false;
      }
      let reader = new FileReader();
      //读取为base64
      reader.readAsDataURL(file);
      // 读取操作完成触发
      reader.onload = (e) => {
        let data;
        if (typeof e.target.result === "object") {
          // 把Array Buffer转化为blob 如果是base64不需要
          data = window.URL.createObjectURL(new Blob([e.target.result])); // 转化为url
        } else {
          data = e.target.result;
        }
        // 因为调用了readAsDataURL方法规定将文件读取为base64,所以data为当前选择文件的base64形式
        this.option.img = data;
      };
    },
    //实时预览函数
    realTime(data) {
      this.previews = data;
    },
    // 点击裁剪,这一步是可以拿到处理后的地址
    finish() {
      console.log(this.$refs.cropper, ".this.$refs.cropper");
      this.$refs.cropper.getCropBlob((data) => {
        this.loading = true;
        let url = window.URL.createObjectURL(data); // 生成data的URl
        this.previewsUrl = url || "";
        this.visible = false;
        var cookie = $utils.getCookieArray();
        var formData = new FormData();
        formData.append("file", data, "this.fileName");
        formData.append("sign", "sdeweEFr@#$@");
        formData.append("t", new Date().getTime() + "");
        formData.append("stk", cookie.token);
        var configs = {
          headers: {
            "Content-Type": "multipart/form-data",
          },
        };
        const Axios = axios.create({
          baseURL: process.env.UPLOAD_URL,
          //   baseURL,
          timeout: 10000,
        });
        Axios.post(`/IFUserHeadUploadFile`, formData, configs)
          .then((res) => {
            if (res.data.code == "0") {
              this.$axios
                .post(`/UserCenter/IFAppModifyUserInfo`, {
                  avatar: res.data.data.url,
                })
                .then((res) => {
                  this.$emit("getUserInfo");
                  this.$message.success("头像上传成功");
                })
                .catch((err) => {
                  this.$message.error(err.message);
                });
            }
          })
          .catch((err) => {
            this.$message.error(err.message);
          });
      });
    },
  },
};
</script>

<style lang="less" scoped>
.HeadEdit {
  padding-top: 70px;
  .icon-img {
    margin-bottom: 40px;
    text-align: center;
    .img {
      display: inline-block;
      width: 168px;
      height: 168px;
      border-radius: 50%;
    }
  }
  .middle {
    text-align: center;
    margin-bottom: 19px;
    .button {
      display: inline-block;
      width: 120px;
      height: 34px;
      background: @heavyDarkColor;
      line-height: 34px;
      border-radius: 8px;
      cursor: pointer;
      text-align: center;
      font-size: 14px;
      font-weight: bold;
      color: @defaultColor;
    }
  }
  .bottom {
    text-align: center;
    height: 24px;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: @darkColor;
    padding-bottom: 61px;
  }
}
.cropper-content {
  .cropper {
    width: auto;
    height: 280px;
  }
}
.content {
  clear: both;
  overflow: hidden;
  height: 280px;
  display: flex;
  position: relative;
  .left {
    width: 280px;
    float: left;
  }
  .child {
    text-align: center;
    position: absolute;
    right: 0;
    width: 232px;
    height: 232px;
    float: right;
    font-size: 12px;
    line-height: 18px;
    color: @darkColor;
    .show-preview1 {
      flex: 1;
      -webkit-flex: 1;
      display: flex;
      height: 182px;
      display: -webkit-flex;
      justify-content: center;
      position: absolute;
      top: -62px;
      left: 70px;
      .preview {
        overflow: hidden;
        transform: scale(0.446428);
        border-radius: 50%;
        background: @defaultColor;
        .img {
          width: 100px;
          height: 100px;
        }
      }
    }
    .show-preview2 {
      position: absolute;
      top: 52px;
      left: 70px;
      .preview {
        transform: scale(0.2232);
        border-radius: 50%;
        overflow: hidden;
        background: @defaultColor;
      }
    }
    .show-preview3 {
      position: absolute;
      top: 132px;
      left: 70px;
      .preview {
        overflow: hidden;
        background: @defaultColor;
        border-radius: 50%;
        transform: scale(0.1339);
      }
    }
  }
  .text {
    width: 86px;
    height: 14px;
    font-size: 12px;
    line-height: 14px;
    text-align: center;
    right: 6px;
    color: @darkColor;
    position: absolute;
  }
  .text1 {
    top: 108px;
  }
  .text2 {
    top: 196px;
  }
  .text3 {
    top: 264px;
  }
}
.btn {
  height: 14px;
  font-size: 14px;
  line-height: 14px;
  color: @primaryColor;
  margin-top: 12px;
  cursor: pointer;
  display: block;
}
.footer {
  height: 114px;
  border-top: none;
  padding-top: 40px;
  padding-left: 63px;
  .cancel {
    width: 128px;
    height: 34px;
    background: @heavyDarkColor;
    border-radius: 8px;
    cursor: pointer;
    line-height: 34px;
    font-size: 14px;
    text-align: center;
    font-weight: bold;
    color: @defaultColor;
    display: inline-block;
    float: left;
  }
  .cancel:hover {
    color: @brightColor;
  }
  .submit {
    width: 128px;
    margin-left: 54px;
    height: 34px;
    background: linear-gradient(90deg, #e5bc7e 0%, #b28c55 100%);
    border-radius: 8px;
    cursor: pointer;
    line-height: 34px;
    font-size: 14px;
    text-align: center;
    font-weight: bold;
    color: #2f2c35;
    display: inline-block;
    float: left;
  }
}
</style>
<style>
.cut-pic {
  width: 452px !important;
}
.cut-pic * {
  box-sizing: border-box;
}
.cut-pic .ant-modal-content {
  background: linear-gradient(135deg, #34343a 0%, #201e1e 100%);
  box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.2);
  border-radius: 8px;
}
.cut-pic .ant-modal-title {
  color: #fff;
}
.cut-pic .ant-modal-close {
  color: #fff;
  margin-top: 20px;
  margin-right: -4px;
}
.cut-pic .ant-modal-close:hover {
  color: #cfad7a;
}
.cut-pic .ant-modal-header {
  height: 88px;
  padding: 40px 16px 0;
  font-weight: bold;
  font-size: 20px;
  background: initial;
  border-bottom: none;
  color: #fff;
  box-sizing: border-box;
}
.cut-pic .ant-modal-body {
  padding: 0 16px;
}
.cut-pic .cropper-crop-box {
  border-radius: 150px;
  overflow: hidden;
}
</style>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

短暂又灿烂的

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

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

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

打赏作者

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

抵扣说明:

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

余额充值