>웹 프론트엔드 >JS 튜토리얼 >온라인 이미지 자르기 구성 요소 기능을 구현하기 위해 Cropper.js를 사용하여 vue를 캡슐화하는 방법(자세한 튜토리얼)

온라인 이미지 자르기 구성 요소 기능을 구현하기 위해 Cropper.js를 사용하여 vue를 캡슐화하는 방법(자세한 튜토리얼)

亚连
亚连원래의
2018-06-02 11:06:241826검색

이 글은 Vue를 캡슐화한 Cropper.js 기반의 온라인 이미지 자르기 구성 요소 기능을 주로 소개합니다. 매우 훌륭하고 참고할 만한 가치가 있습니다. 필요한 친구들이 참고할 수 있습니다.

렌더링은 아래와 같습니다.

github : 데모 다운로드

cropper.js

github:cropper.js

공식 웹사이트(데모)

cropper.js 설치

  • npm 또는 Bower 설치

npm install cropper
# or
bower install cropper

복제 다운로드: 주소

git clone https://github.com/fengyuanchen/cropper.git

참조 Cropper.js

주로 Cropper.js와 Cropper.css 두 파일을 참조합니다

<script src="/path/to/jquery.js"></script><!-- jQuery is required -->
<link href="/path/to/cropper.css" rel="external nofollow" rel="stylesheet">
<script src="/path/to/cropper.js"></script>

참고: jquery 파일을 도입해야 합니다. Cropper.js 플러그인을 사용하기 전에

사용하기 쉽습니다

스크린샷에 사용되는 p 컨테이너를 빌드하세요

<!-- Wrap the image or canvas element with a block element (container) -->
<p>
 ![](picture.jpg)
</p>

컨테이너의 스타일을 추가하고 img가 전체 컨테이너를 채우도록 하세요(매우 중요)

/* Limit image width to avoid overflow the container */
img {
 max-width: 100%; /* This rule is very important, please do not ignore this! */
}

cropper.js 메소드를 호출하여 스크린샷 초기화 Control

$(&#39;#image&#39;).cropper({
 aspectRatio: 16 / 9,
 crop: function(e) {
 // Output the result data for cropping image.
 console.log(e.x);
 console.log(e.y);
 console.log(e.width);
 console.log(e.height);
 console.log(e.rotate);
 console.log(e.scaleX);
 console.log(e.scaleY);
 }
});

기타 자세한 API는 github:cropper.js

vue 컴포넌트로 캡슐화됨

vue 컴포넌트로 패키징할 때 해결해야 할 문제

  • cropper.js 관련

시뮬레이션 입력 이미지를 선택하고 선택한 이미지의 형식과 크기를 제한하려면 상자를 클릭하세요.

자를 이미지를 다시 선택하세요

자르기를 확인하고 다음에서 이미지 정보를 얻으세요. base64 형식

  • vue 관련

상위-하위 구성 요소가 아닌 구성 요소 간의 통신 문제

입력 상자 클릭을 시뮬레이션하여 사진을 선택하고 선택한 사진의 형식과 크기를 제한합니다

숨겨진 입력 구축 태그를 지정한 다음 이 입력을 클릭하여 사진 선택 기능을 구현합니다

<!-- input框 -->
<input id="myCropper-input" type="file" :accept="imgCropperData.accept" ref="inputer" @change="handleFile">
//模拟点击
document.getElementById(&#39;myCropper-input&#39;).click();

모니터를 입력에 바인딩합니다. 내용을 변경하는 방법은 업로드된 파일을 가져와서 형식과 크기를 확인하는 것입니다

// imgCropperData: {
// accept: &#39;image/gif, image/jpeg, image/png, image/bmp&#39;,
// }
handleFile (e) {
 let _this = this;
 let inputDOM = this.$refs.inputer;
 // 通过DOM取文件数据
 _this.file = inputDOM.files[0];
 // 判断文件格式
 if (_this.imgCropperData.accept.indexOf(_this.file.type) == -1) {
 _this.$Modal.error({
  title: &#39;格式错误&#39;,
  content: &#39;您选择的图片格式不正确!&#39;
 });
 return;
 }
 // 判断文件大小限制
 if (_this.file.size > 5242880) {
 _this.$Modal.error({
  title: &#39;超出限制&#39;,
  content: &#39;您选择的图片过大,请选择5MB以内的图片!&#39;
 });
 return;
 }
 var reader = new FileReader();
 // 将图片将转成 base64 格式
 reader.readAsDataURL(_this.file);
 reader.onload = function () {
 _this.imgCropperData.imgSrc = this.result;
 _this.initCropper();
 }
}

다시 선택하세요 자르기용 이미지

이미지를 처음 선택하면 반드시 이미지를 다시 선택해야 하는 문제에 직면하게 되며, 이미지를 선택한 후 자르기 상자에서 이미지를 바꾸는 방법에 직면하게 됩니다. 위의 단계에서 FileRender() 메서드를 통해 이미지의 주요 정보를 얻을 수 있습니다. 이제 문제를 해결하려면 자르기 상자를 다시 빌드해야 합니다. 공식 데모에서 공식 메서드를 사용하는 것을 발견했습니다. 작동할 자르기 컨테이너를 동적으로 추가하는 방법 여기서는 공식 구현을 모방합니다.

// 初始化剪切
 initCropper () {
 let _this = this;
 // 初始化裁剪区域
 _this.imgObj = $(&#39;![](&#39; + _this.imgCropperData.imgSrc + &#39;)&#39;);
 let $avatarPreview = $(&#39;.avatar-preview&#39;);
 $(&#39;#myCropper-workspace&#39;).empty().html(_this.imgObj);
 _this.imgObj.cropper({
  aspectRatio: _this.proportionX / _this.proportionY,
  preview: $avatarPreview,
  crop: function(e) {

  }
 });
 }

잘라내기 확인 및 base64 형식의 이미지 정보 가져오기

let $imgData = _this.imgObj.cropper(&#39;getCroppedCanvas&#39;)
imgBase64Data = $imgData.toDataURL(&#39;image/png&#39;);

업로드용 데이터 구성

// 构造上传图片的数据
let formData = new FormData();
// 截取字符串
let photoType = imgBase64Data.substring(imgBase64Data.indexOf(",") + 1);
//进制转换
const b64toBlob = (b64Data, contentType = &#39;&#39;, sliceSize = 512) => {
 const byteCharacters = atob(b64Data);
 const byteArrays = [];
 for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
 const slice = byteCharacters.slice(offset, offset + sliceSize);
 const byteNumbers = new Array(slice.length);
 for(let i = 0; i < slice.length; i++) {
  byteNumbers[i] = slice.charCodeAt(i);
 }
 const byteArray = new Uint8Array(byteNumbers);
 byteArrays.push(byteArray);
 }
 const blob = new Blob(byteArrays, {
 type: contentType
 });
 return blob;
}
const contentType = &#39;image/jepg&#39;;
const b64Data2 = photoType;
const blob = b64toBlob(b64Data2, contentType);
formData.append("file", blob, "client-camera-photo.png")
formData.append("type", _this.imgType)

상위-하위 구성요소가 아닌 구성요소 간의 통신 문제

이전 프로젝트에서는 상위-하위 구성이 일반적으로 사용되었습니다. 컴포넌트 간의 통신 매개변수는 일반적으로 두 가지 방법을 사용합니다

라우터에 매개변수를 배치한 다음, Route.params.xxx 또는 Route.query.xxx를 호출하여 이를 얻습니다.

props를 통한 통신

여기서는 컴포넌트 간 통신을 위한 eventBus를 사용합니다

Steps

1. B 구성 요소가 A 구성 요소에 매개 변수를 전달하도록 버스 구성 요소를 선언합니다

//bus.js
import Vue from &#39;vue&#39;; 
export default new Vue();

2. A 구성 요소의 버스 구성 요소를 참조하고 실시간 매개 변수 변경 사항을 들어보세요

// A.vue
import Bus from &#39;../../components/bus/bus.js&#39;
export default {
 components: { Bus },
 data () {},
 created: function () {
 Bus.$on(&#39;getTarget&#39;, imgToken => { 
  var _this = this;
  console.log(imgToken);
  ... 
 }); 
 }
}

3. 버스 구성 요소는 매개 변수를 구성 요소 A

// B.vue
// 传参
Bus.$emit(&#39;getTarget&#39;, imgToken);

에 전달하기 위해 구성 요소 B에서도 참조됩니다. 참조:

vue-$on
vue-$emit
vue.js road (4) - .0s의 vue2 EventBus는 형제 구성 요소 통신을 구현합니다

vue 사진 선택 및 스크린샷 플러그인 전체 코드

<template>
 <p class="myCropper-container">
 <p id="myCropper-workspace">
  <p class="myCropper-words" v-show="!imgCropperData.imgSrc">请点击按钮选择图片进行裁剪</p>
 </p>
 <p class="myCropper-preview" :class="isShort ? &#39;myCropper-preview-short&#39; : &#39;myCropper-preview-long&#39;">
  <p class="myCropper-preview-1 avatar-preview">
  ![](!imgCropperData.imgUploadSrc ? &#39;/images/thumbnail/thumbnail-img.jpg&#39; : imgCropperData.imgUploadSrc)
  </p>
  <p class="myCropper-preview-2 avatar-preview">
  ![](!imgCropperData.imgUploadSrc ? &#39;/images/thumbnail/thumbnail-img.jpg&#39; : imgCropperData.imgUploadSrc)
  </p>
  <p class="myCropper-preview-3 avatar-preview">
  ![](!imgCropperData.imgUploadSrc ? &#39;/images/thumbnail/thumbnail-img.jpg&#39; : imgCropperData.imgUploadSrc)
  </p>
  <input id="myCropper-input" type="file" :accept="imgCropperData.accept" ref="inputer" @change="handleFile">
  <Button type="ghost" class="myCropper-btn" @click="btnClick">选择图片</Button>
  <Button type="primary" class="myCropper-btn" :loading="cropperLoading" @click="crop_ok">确认</Button>
 </p>
 </p>
</template>
<script>
 var ezjsUtil = Vue.ezjsUtil;
 import Bus from &#39;./bus/bus.js&#39; 
 export default {
 components: { Bus },
 props: {
  imgType: {
  type: String
  },
  proportionX: {
  type: Number
  },
  proportionY: {
  type: Number
  }
 },
 data () {
  return {
  imgCropperData: {
   accept: &#39;image/gif, image/jpeg, image/png, image/bmp&#39;,
   maxSize: 5242880,
   file: null, //上传的文件
   imgSrc: &#39;&#39;, //读取的img文件base64数据流
   imgUploadSrc: &#39;&#39;, //裁剪之后的img文件base64数据流
  },
  imgObj: null,
  hasSelectImg: false,
  cropperLoading: false,
  isShort: false,
  }
 },
 created: function () {
  let _this = this;
 },
 mounted: function () {
  let _this = this;
  // 初始化预览区域
  let maxWidthNum = Math.floor(300 / _this.proportionX);
  let previewWidth = maxWidthNum * _this.proportionX;
  let previewHeight = maxWidthNum * _this.proportionY;
  if (previewWidth / previewHeight <= 1.7) {
  previewWidth = previewWidth / 2;
  previewHeight = previewHeight / 2;
  _this.isShort = true;
  }
  // 设置最大预览容器的宽高
  $(&#39;.myCropper-preview-1&#39;).css(&#39;width&#39;, previewWidth + &#39;px&#39;);
  $(&#39;.myCropper-preview-1&#39;).css(&#39;height&#39;, previewHeight + &#39;px&#39;);
  // 设置中等预览容器的宽高
  $(&#39;.myCropper-container .myCropper-preview .myCropper-preview-2&#39;).css(&#39;width&#39;,( previewWidth / 2) + &#39;px&#39;);
  $(&#39;.myCropper-container .myCropper-preview .myCropper-preview-2&#39;).css(&#39;height&#39;, (previewHeight / 2) + &#39;px&#39;);
  // 设置最小预览容器的宽高
  $(&#39;.myCropper-container .myCropper-preview .myCropper-preview-3&#39;).css(&#39;width&#39;,( previewWidth / 4) + &#39;px&#39;);
  $(&#39;.myCropper-container .myCropper-preview .myCropper-preview-3&#39;).css(&#39;height&#39;, (previewHeight / 4) + &#39;px&#39;);
 },
 methods: {
  // 点击选择图片
  btnClick () {
  let _this = this;
  // 模拟input点击选择文件
  document.getElementById(&#39;myCropper-input&#39;).click();
  },
  // 选择之后的回调
  handleFile (e) {
  let _this = this;
  let inputDOM = this.$refs.inputer;
  // 通过DOM取文件数据
  _this.file = inputDOM.files[0];
  // 判断文件格式
  if (_this.imgCropperData.accept.indexOf(_this.file.type) == -1) {
   _this.$Modal.error({
   title: &#39;格式错误&#39;,
   content: &#39;您选择的图片格式不正确!&#39;
   });
   return;
  }
  // 判断文件大小限制
  if (_this.file.size > 5242880) {
   _this.$Modal.error({
   title: &#39;超出限制&#39;,
   content: &#39;您选择的图片过大,请选择5MB以内的图片!&#39;
   });
   return;
  }
  var reader = new FileReader();
  // 将图片将转成 base64 格式
  reader.readAsDataURL(_this.file);
  reader.onload = function () {
   _this.imgCropperData.imgSrc = this.result;
   _this.initCropper();
  }
  },
  // 初始化剪切
  initCropper () {
  let _this = this;
  // 初始化裁剪区域
  _this.imgObj = $(&#39;![](&#39; + _this.imgCropperData.imgSrc + &#39;)&#39;);
  let $avatarPreview = $(&#39;.avatar-preview&#39;);
  $(&#39;#myCropper-workspace&#39;).empty().html(_this.imgObj);
  _this.imgObj.cropper({
   aspectRatio: _this.proportionX / _this.proportionY,
   preview: $avatarPreview,
   crop: function(e) {
   }
  });
  _this.hasSelectImg = true;
  },
  // 确认
  crop_ok () {
  let _this = this, imgToken = null, imgBase64Data = null;
  // 判断是否选择图片
  if (_this.hasSelectImg == false) {
   _this.$Modal.error({
   title: &#39;裁剪失败&#39;,
   content: &#39;请选择图片,然后进行裁剪操作!&#39;
   });
   return false;
  }
  // 确认按钮不可用
  _this.cropperLoading = true;
  let $imgData = _this.imgObj.cropper(&#39;getCroppedCanvas&#39;)
  imgBase64Data = $imgData.toDataURL(&#39;image/png&#39;); 
  // 构造上传图片的数据
  let formData = new FormData();
  // 截取字符串
  let photoType = imgBase64Data.substring(imgBase64Data.indexOf(",") + 1);
  //进制转换
    const b64toBlob = (b64Data, contentType = &#39;&#39;, sliceSize = 512) => {
     const byteCharacters = atob(b64Data);
     const byteArrays = [];
     for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
      const slice = byteCharacters.slice(offset, offset + sliceSize);
      const byteNumbers = new Array(slice.length);
      for(let i = 0; i < slice.length; i++) {
       byteNumbers[i] = slice.charCodeAt(i);
      }
      const byteArray = new Uint8Array(byteNumbers);
      byteArrays.push(byteArray);
     }
     const blob = new Blob(byteArrays, {
      type: contentType
     });
     return blob;
  }
  const contentType = &#39;image/jepg&#39;;
    const b64Data2 = photoType;
  const blob = b64toBlob(b64Data2, contentType);
  formData.append("file", blob, "client-camera-photo.png")
  formData.append("type", _this.imgType)
  // ajax上传
  $.ajax({
     url: _this.$nfs.uploadUrl,
     method: &#39;POST&#39;,
     data: formData,
     // 默认为true,设为false后直到ajax请求结束(调完回掉函数)后才会执行$.ajax(...)后面的代码
     async: false,
     // 下面三个,因为直接使用FormData作为数据,contentType会自动设置,也不需要jquery做进一步的数据处理(序列化)。
     cache: false,
     contentType: false,
   processData: false,
   type: _this.imgType,
     success: function(res) {
   let imgToken = res.data.token;
   _this.cropperLoading = false;
   // 传参
   Bus.$emit(&#39;getTarget&#39;, imgToken); 
     },
     error: function(error) {
   _this.cropperLoading = false;
   _this.$Modal.error({
    title: &#39;系统错误&#39;,
    content: &#39;请重新裁剪图片进行上传!&#39;
   });
     }
    });
  },
 }
 }
</script>
<style lang="less" scoped>
 .myCropper-container {
 height: 400px;
 }
 .myCropper-container #myCropper-input {
 width: 0px;
 height: 0px;
 }
 .myCropper-container #myCropper-workspace {
 width: 500px;
 height: 400px;
 border: 1px solid #dddee1;
 float: left;
 }
 // 裁剪图片未选择图片的提示文字
 .myCropper-container #myCropper-workspace .myCropper-words{
 text-align: center;
 font-size: 18px;
 padding-top: 180px;
 }
 // 裁剪图片的预览区域
 .myCropper-container .myCropper-preview-long {
 width: 300px;
 }
 .myCropper-container .myCropper-preview-short {
 width: 200px;
 }
 .myCropper-container .myCropper-preview {
 float: left;
 height: 400px;
 margin-left: 10px;
 }
 .myCropper-container .myCropper-preview .myCropper-preview-1 {
 border-radius: 5px;
 overflow: hidden;
 border: 1px solid #dddee1;
 box-shadow: 3px 3px 3px #dddee1;
 img {
  width: 100%;
  height: 100%;
 }
 }
 .myCropper-container .myCropper-preview .myCropper-preview-2 {
 margin-top: 20px;
 border-radius: 5px;
 overflow: hidden;
 border: 1px solid #dddee1;
 box-shadow: 3px 3px 3px #dddee1;
 img {
  width: 100%;
  height: 100%;
 }
 }
 .myCropper-container .myCropper-preview .myCropper-preview-3 {
 margin-top: 20px;
 border-radius: 5px;
 overflow: hidden;
 border: 1px solid #dddee1;
 box-shadow: 3px 3px 3px #dddee1;
 img {
  width: 100%;
  height: 100%;
 }
 }
 // 按钮
 .myCropper-btn {
 float: left;
 margin-top: 20px;
 margin-right: 10px;
 }
</style>

BY-LucaLJX

github: lucaljx

위 내용은 제가 모든 사람을 위해 편집한 내용입니다. 앞으로 모든 사람에게 도움이 되기를 바랍니다.

관련글 :

자바스크립트 내비게이션 바 구현 방법

pm2를 사용하여 도메인 이름 구매부터 node.js 프로젝트 배포까지 전체 과정에 대한 자세한 설명

layui select 동적으로 옵션 추가 예시

위 내용은 온라인 이미지 자르기 구성 요소 기능을 구현하기 위해 Cropper.js를 사용하여 vue를 캡슐화하는 방법(자세한 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.