1.1.1 • Published 2 days ago

mui-image-crop v1.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 days ago

mui-image-crop

NPM version NPM downloads

使用 MUI(@mui/material)时类似 antd Upload 组件 picture-card 预览样式的 image Crop。默认具有缩放、旋转、宽高比工具栏,支持自定义

主要是自用,默认预览样式部分直接使用的 antd upload 组件的 picture-card 的样式。

安装

npm i mui-image-crop

使用

如果时 es 模式直接:

import React, {useState} from 'react';
import ImageCrop from 'mui-image-crop';

const Sample = (props) => {
  const [value, setValue] = props;
  return (
    <ImageCrop
      value={value}
      onChange={setValue}
      preview
    >
  )
}

如果发现缺少默认的样式(一个 104*104)的方框,则需手动导入 css(es 模块可不需要手动导入):

import 'mui-image-crop/dist/style.css';

自定义

本组件可接收 children,children 会作为 uploader(点击或拖拽上传)使用,无 children 时,默认为 antd Upload 组件的 picture-card 样式。也可以通过 uploaderProps 进行自定义容器样式,比如不需要预览,只需要一个按钮作为上传组件:

<ImageCrop
  preview={false}
  uploaderProps={{
    style: {
      border: 'none',
      width: 'auto',
      height: 'auto',
    },
  }}
  // showAspectToolbar={false}
  // aspect={1}
  // onFinish={onFinish}
>

可以自定义 onFinish 来进行结果提交,onFinish 为一个异步函数,参数就是 value ({name,url,size,originFile:File}),其中 name 为文件名,url 为 base64 字符串,originFile 为文件对象,如果返回 true,则对话框会自动关闭

支持的 props

ImageCrop.propTypes = {
  value: PropTypes.any,
  onChange: PropTypes.func,
  disabled: PropTypes.bool,
  error: PropTypes.bool,

  preview: PropTypes.bool, // true

  children: PropTypes.node,
  imageCropDialogProps: PropTypes.object,
  cropperContainerStyle: PropTypes.object,
  imageCropDialogContentRootStyle: PropTypes.object,

/*0.x样式为.xx或[.xx], 1.x为{image/*:[.xxx]} */
  accept: PropTypes.any),

  imageCardProps: PropTypes.shape(imageCardPropTypes),
  uploaderProps: PropTypes.shape(uploaderPropsTypes),

  ...imageCropPropTypes,
  ...imageCropSelfDefinePropTypes,
};

其中imageCropPropTypes主要为react-easy-crop的 props:

const imageCropPropTypes = {
  showGrid: PropTypes.bool, // 是否显示网格 true
  restrictPosition: PropTypes.bool,
  object: PropTypes.oneOf(['contain', 'horizontal-cover', 'vertical-cover']), // 'contain'
  crop: PropTypes.shape({
    x: PropTypes.number,
    y: PropTypes.number,
  }),
  cropShape: PropTypes.oneOf(['rect', 'round']), // 'rect'
  cropSize: PropTypes.shape({
    width: PropTypes.number,
    height: PropTypes.number,
  }),
  onCropChange: PropTypes.func, // crop: {x: number,y: number} => void
  onCropSizeChange: PropTypes.func, // cropSize: {width: number,height: number} => void
  onCropComplete: PropTypes.func, // (croppedArea: {x: number,y: number,width: number,height: number},croppedAreaPixels: {x: number,y: number,width: number,height: number})=>void
  onCropAreaChange: PropTypes.func, // (croppedArea: {x: number,y: number,width: number,height: number},croppedAreaPixels: {x: number,y: number,width: number,height: number})=>void
  initialCroppedAreaPercentages: PropTypes.shape({
    width: PropTypes.number,
    height: PropTypes.number,
    x: PropTypes.number,
    y: PropTypes.number,
  }),
  initialCroppedAreaPixels: PropTypes.shape({
    width: PropTypes.number,
    height: PropTypes.number,
    x: PropTypes.number,
    y: PropTypes.number,
  }),
  aspect: PropTypes.number, // 4/3
  zoom: PropTypes.number,
  minZoom: PropTypes.number, // 1
  maxZoom: PropTypes.number, // 3
  zoomSpeed: PropTypes.number, // 1
  zoomWithScroll: PropTypes.bool, // true
  onZoomChange: PropTypes.func, // zoom: number => void
  rotation: PropTypes.number,
  onRotationChange: PropTypes.func, // rotation: number => void
  transform: PropTypes.string, // `translate(${crop.x}px, ${crop.y}px) rotate(${rotation}deg) scale(${zoom})`
  mediaProps: PropTypes.object,
  style: PropTypes.shape({
    containerStyle: PropTypes.object,
    mediaStyle: PropTypes.object,
    cropAreaStyle: PropTypes.object,
  }),
  classes: PropTypes.shape({
    containerClassName: PropTypes.string,
    mediaClassName: PropTypes.string,
    cropAreaClassName: PropTypes.string,
  }),
  onInteractionStart: PropTypes.func, // () => void
  onInteractionEnd: PropTypes.func, // () => void
  onMediaLoaded: PropTypes.func, // mediaSize: {width: number,height: number,naturalWidth: number,naturalHeight: number}=>void
  onTouchRequest: PropTypes.func, // (e: React.TouchEvent<HTMLDivElement>) => boolean
  onWheelRequest: PropTypes.func, // (e: WheelEvent) => boolean
  disableAutomaticStylesInjection: PropTypes.bool, // Whether to auto inject styles using a style tag in the document head on component mount. When disabled you need to import the css file into your application manually (style file is available in react-easy-crop/react-easy-crop.css). Example with sass/scss @import "~react-easy-crop/react-easy-crop";.
};

imageCropSelfDefinePropTypes是一些自定义的 props:

const imageCropSelfDefinePropTypes = {
  qulity: PropTypes.number,
  imageType: PropTypes.string, // 剪裁后图片类型,默认为原图片类型,如果不自持一般会自动置为 image/png
  title: PropTypes.node, // 剪裁框的标题
  TitleRender: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // props: title
  showAspectToolbar: PropTypes.bool, // 是否显示宽高比工具栏
  showRotateToolbar: PropTypes.bool, // 是否显示旋转工具栏
  showZoomToolbar: PropTypes.bool, // 是否显示缩放工具栏
  ToolbarRender: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // 工具栏组件,以下props会被注入 props:zoom, onZoomChange, minZoom, maxZoom, zoomStep, showZoomToolbar, rotation, onRotationChange, rotateStep, showRotateToolbar, aspect, onAspectChange, showAspectToolbar, aspectMarks, onReset, onClose, onFinish, width, defaultAspect
  ActionsRender: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // DialogActions组件,以下props会被注入: props: onReset, onClose, onFinish, resetText, okText, cancelText
  okText: PropTypes.node, // 确认按钮内容 OK
  resetText: PropTypes.node, // 重置按钮内容 Reset
  cancelText: PropTypes.node, // 取消按钮内容 Cancel
  allowTouchRotate: PropTypes.bool, // 是否允许触摸旋转 false
  defaultAspect: PropTypes.number, // 默认的宽高比
  onAspectChange: PropTypes.func, // 宽高比变化触发 api: (aspect) => void
  aspectMarks: PropTypes.arrayOf(
    PropTypes.shape({
      value: PropTypes.number,
      label: PropTypes.any,
    }),
  ), // 可选宽高比列表  [   { value: 0.25, label: '1:4' },  { value: 0.33, label: '1:3' },  { value: 0.5, label: '1:2' },  { value: 0.75, label: '3:4' },  { value: 1, label: '1:1' },  { value: 1.33, label: '4:3' },  { value: 2, label: '2:1' },  { value: 3, label: '3:1' },  { value: 4, label: '4:1' }, ]
  zoomStep: PropTypes.number, // 缩放时的步长(百分比) 0.1
  rotateStep: PropTypes.number, // 旋转时的角度步长 1
  onFinish: PropTypes.func, // (v:{name,url,size,originFile:File})=> boolen?  if return false, will not close
};

imageCardPropTypes为剪裁图片后的预览卡片的相关样式(如果不需要预览可以preview置为 false):

const imageCardPropTypes = {
  style: PropTypes.object,
  className: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    PropTypes.array,
    PropTypes.object,
  ]),
  showDownloadIcon: PropTypes.bool,
  showPreviewIcon: PropTypes.bool,
  showRemoveIcon: PropTypes.bool,
  customDownloadIcon: PropTypes.node,
  customPreviewIcon: PropTypes.node,
  customRemoveIcon: PropTypes.node,
  onDownload: PropTypes.func,
  onPreview: PropTypes.func,
  onRemove: PropTypes.func,
  downloadText: PropTypes.string,
  previewText: PropTypes.string,
  removeText: PropTypes.string,
};

cropActionsPropTypes为剪切窗口的底部按钮 props:

const cropActionsPropTypes = {
  resetText: PropTypes.node,
  okText: PropTypes.node,
  cancelText: PropTypes.node,
};

uploaderPropsTypes为点击或拖拽上传组件的 props(实际为react-dropzone的部分 props):

const uploaderPropsTypes = {
  style: PropTypes.object,
  className: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    PropTypes.array,
    PropTypes.object,
  ]),
  minSize: PropTypes.number, // Minimum file size (in bytes)
  maxSize: PropTypes.number, // Maximum file size (in bytes)
  useFsAccessApi: PropTypes.bool, // Set to true to use the https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API  to open the file picker instead of using an `<input type="file">` click event.
};