this.cropper.getCroppedCanvas is not a function如何解决(React-Cropper)

在React-Cropper实现图片裁剪的使用中 在使用这段代码的时候 报错

解决方法一

查看你的  react-cropper版本 我这里的版本是

你可以将 react-cropper的版本降到 "react-cropper": "^1.2.0"  1.*的版本即可

解决方法二(推荐):

按照官方的解释,2.*版本开始弃用ref 的形式 而使用  onInitialized

 

附上组件代码供参考

import React ,{Component} from 'react'
import request from "umi-request";
import './index.less'
import Cropper from 'react-cropper' // 引入Cropper
import 'cropperjs/dist/cropper.css' // 引入Cropper对应的css
import { Button } from 'antd';
import {dataURLtoFile} from '@/utils'
import {uploadCropperImg} from '@/api'
interface CropperImgProps {
  uploadedImageFile:any
  onClose:Function
  onSubmit:Function
}
interface CropperImgState {
  src:string,
  submitting:boolean

}
class CropperImg extends Component<CropperImgProps, CropperImgState>{
  state = {
    src:'',
    submitting:false
  }
  cropper: any

  componentDidMount() {
    const fileReader = new FileReader()
    fileReader.onload =(e:any) => {
      const dataURL = e.target.result
      console.log(e)
      this.setState({ src: dataURL })
    }

    fileReader.readAsDataURL(this.props.uploadedImageFile)
  }
  handleSubmit = () => {
    if (!this.state.submitting) {

      let dataurl = this.cropper.getCroppedCanvas().toDataURL()


      let formData = new FormData()
      let newFile = dataURLtoFile(dataurl,this.props.uploadedImageFile.name)
      formData.append('file', newFile)


        uploadCropperImg(formData).then(res => {
          console.log('res====',res)
          if(res.code == 200){
            console.log(res.data)
            this.props.onSubmit(res.data)

          }
        })


    }
    this.props.onClose()
  }
  onCropperInit=(cropper:any) => { this.cropper = cropper }

  render() {
    return (
      <div className="class-cropper-modal">

        <div className="modal-panel">
          <div className="cropper-container-container">
            <div className="cropper-container">
              <Cropper
                src={this.state.src}
                className="cropper"
                // ref={cropper => (this.cropper = cropper)}
                // Cropper.js options
                onInitialized={this.onCropperInit.bind(this)}
                viewMode={1}
                zoomable={true}
                aspectRatio={1} // 固定为1:1  可以自己设置比例, 默认情况为自由比例
                guides={false}
                preview=".cropper-preview"
              />

            </div>
            <div className="preview-container">
              <div className="cropper-preview" />
            </div>
          </div>
          <div className="button-row">
            <Button type="primary" onClick={this.handleSubmit}>点击提交</Button>
            <Button style={{ marginLeft: '100px' }} onClick={() => this.props.onClose()}>取消</Button>
            {/*<div className="submit-button" onClick={this.handleSubmit}>*/}
            {/*  点击提交*/}
            {/*</div>*/}
          </div>
        </div>
      </div>
    )
  }
}

export default CropperImg

补充:父组件代码

import React, { Component, useState } from 'react';
import { Tabs, Modal, Button, Input, Radio, message, Select,DatePicker, Space } from 'antd';
import styles from './index.less';
import moment from 'moment'
import { AppStoreProps } from '@/store/appStore';
import { inject, observer } from 'mobx-react';
import CropperImg from '@/components/CropperImg';
import {updateUserInfo} from '@/api'
import userMessageStore, { UserMessageStoreProps } from '@/pages/UserCenter/UserMessage/store';
import { FormOutlined } from '@ant-design/icons';
const { TabPane } = Tabs;
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 文件最大限制为5M
const { Option } = Select;
const dateFormat = 'YYYY-MM-DD'
function callback(key: string) {
  console.log(key);
}

interface UserMessageProps {
  appStore: AppStoreProps
  userMessageStore: UserMessageStoreProps

}

interface UserMessageState {
  isShowCopper: boolean
  classModalFile: any
  classModalVisible: boolean
  classResultImgUrl: String
  isChange:Boolean, //是否编辑
  // account,education,name,degree,gender,email,userBirthday,idCard
  account:String,
  education:String,
  name:String,
  degree:String,
  gender:Number,
  email:String,
  userBirthday:String,
  idCard:String
}

@inject('appStore', 'userMessageStore') @observer
export default class UserMessage extends Component<UserMessageProps, UserMessageState> {
  state = {
    isShowCopper: false,
    classModalFile: null,
    classModalVisible: false,
    classResultImgUrl: this.props.appStore.userInfo.iconUrl,
    isChange:true,
    account:this.props.appStore.userInfo.account,
    education:this.props.appStore.userInfo.education,
    name:this.props.appStore.userInfo.name,
    degree:this.props.appStore.userInfo.degree,
    gender:this.props.appStore.userInfo.gender,
    email:this.props.appStore.userInfo.email,
    userBirthday:this.props.appStore.userInfo.userBirthday,
    idCard:this.props.appStore.userInfo.idCard
  };
  fileInputEl = React.createRef();

  componentDidMount() {
    console.log(this.props.appStore.userInfo, '个人信息');
  }

  upLoadImg = () => {
    this.props.userMessageStore.imgCopperFun();
    this.setState({
      isShowCopper: this.props.userMessageStore.isShowCopper,
    });
  };
  handleGetResultImgUrl = (key: string) => (url: string) => {
    const str = url;

    // @ts-ignore
    this.setState({
      [key]: str,
    },() => {
      this.saveUserInfo()
    });


  };
  handleClassFileChange = (e: any) => {
    const file = e.target.files[0];
    console.log(file,'file')
    if (file) {
      if (file.size <= MAX_FILE_SIZE) {
        this.setState(
          {
            classModalFile: file, // 先把上传的文件暂存在state中
          },
          () => {
            this.setState({
              classModalVisible: true, // 然后弹出modal
            });
          },
        );
      } else {
        message.warning('文件过大');

      }
    }
  };
  changeGender = (e: any) => {
    this.setState({
      gender: e.target.value,
    });
  };
  selectEducation = (value: string) => {

    this.setState({
      education:value
    })
  };
  selectDate = (date:any, dateString:string) => {
    this.setState({
      userBirthday:dateString
    })
  }
  selectAcademic = (value:string) => {

    this.setState({
      degree:value
    })
  }
  changeUserInfo =() => {
    this.setState({
      isChange:false
    })
  }
  cancelChangeUserInfo = () => {
    this.setState({
      isChange:true
    })
  }
  changeAccount = (e:any) => {
    this.setState({
      account:e.target.value
    })
  }
  saveUserInfo = () => {
    let data = {
      "education": this.state.education, //学历
      "gender": this.state.education, //性别(1男,2女)
      "degree": this.state.degree,//学位
      "name": this.state.name,//姓名
      "iconUrl": process.env.VUE_APP_DOWN_API + this.state.classResultImgUrl,//头像
      "email": this.state.email,//邮箱
      "userBirthday": this.state.userBirthday, //生日
      "idCard": this.state.idCard,//身份证号,
      "nation": "汉族",//民族
      "politicCountenance": "中共党员", //政治面貌
      "graduateSchool": "辽宁沈阳农业大学", //毕业院校
    }
    console.log(data)
  }
  changeEmail = (e:any) => {
    this.setState({
      email:e.target.value
    })
  }
  changeName = (e:any) => {
    this.setState({
      name:e.target.value
    })
  }
  changeIdCard = (e:any) => {
    this.setState({
      idCard:e.target.value
    })
  }

  render() {
    const { isShowCopper, classModalFile, classResultImgUrl, classModalVisible,isChange,account,education,name,degree,gender,email,userBirthday,idCard  } = this.state;


    return (
      <div id="usermessage" className={styles.usermessage}>

        <Tabs defaultActiveKey="1" onChange={callback}>
          <TabPane tab="个人资料" key="1" style={{position:'relative'}}>
            <div>
              <span>头像:</span>
              <img className={styles.userimg} src={classResultImgUrl} alt=""/>
              <div className={styles.half_area}>
                <label className="upload-input-label">
                  <Button type="primary" onClick={() =>
                    // @ts-ignore
                    this.fileInputEl.current.click()}>上传图片</Button>
                  <input
                    type="file"
                    hidden
                    // @ts-ignore
                    ref={this.fileInputEl}
                    accept="image/jpeg,image/jpg,image/png"
                    className="base-upload-input"
                    onChange={this.handleClassFileChange}
                  />
                </label>

              </div>

            </div>
            <div className={styles.formOutStyle} onClick={this.changeUserInfo}><FormOutlined /></div>
            <div className={styles.flexBetween}>
              <div className={styles.flexAlignItems}>
                用户名:<div>{account}</div>
              </div>
              <div className={styles.flexAlignItems}>
                性别:<Radio.Group disabled={isChange} value={gender} onChange={this.changeGender} style={{marginLeft:'27px' }}>
                <Radio value={1}>男</Radio>
                <Radio value={2}>女</Radio>
              </Radio.Group>
              </div>
            </div>
            <div className={styles.flexBetween}>
              <div className={styles.flexAlignItems}>
                学历:
                <Select defaultValue={education} disabled={isChange} style={{ width: 200,marginLeft:'13px'  }} onChange={this.selectEducation}>
                  <Option value="专科">专科</Option>
                  <Option value="本科">本科</Option>
                  <Option value="硕士研究生">硕士研究生</Option>
                </Select>
              </div>
              <div className={styles.flexAlignItems}>
                邮箱:<Input placeholder="请输入邮箱" disabled={isChange} onChange={this.changeEmail} value={email} style={{ width: '200px',marginLeft:'27px' }}/>
              </div>
            </div>
            <div className={styles.flexBetween}>
              <div className={styles.flexAlignItems}>
                姓名:<Input placeholder="请输入用户姓名" disabled={isChange} onChange={this.changeName} value={name} style={{ width: '200px',marginLeft:'13px'  }}/>
              </div>
              <div className={styles.flexAlignItems}>
                出生日期:<Space direction="vertical" >
                  <DatePicker disabled={isChange} defaultValue={moment(userBirthday, dateFormat)} format={dateFormat} onChange={this.selectDate} />
                </Space>
              </div>
            </div>
            <div className={styles.flexBetween}>
              <div className={styles.flexAlignItems}>
                学位:
                <Select style={{ width: 200 ,marginLeft:'13px'}} disabled={isChange} defaultValue={degree} onChange={this.selectAcademic}>
                  <Option value="博士">博士</Option>
                  <Option value="硕士">硕士</Option>
                  <Option value="学士">学士</Option>
                </Select>
              </div>
              <div className={styles.flexAlignItems}>
                身份证号:<Input placeholder="请输入身份证号" disabled={isChange} onChange={this.changeIdCard} value={idCard} style={{ width: '200px' }}/>
              </div>
            </div>
            {
              !isChange?
                <div style={{textAlign:'center'}}>
                  <Button onClick={this.cancelChangeUserInfo}>取消</Button>
                  <Button type="primary" onClick={this.saveUserInfo} style={{marginTop:'100px',marginLeft:'100px'}}>保存</Button>
                </div>
                :
                ''
            }
          </TabPane>
          <TabPane tab="职业信息" key="2">
            Content of Tab Pane 2
          </TabPane>
        </Tabs>
        {classModalVisible && (<CropperImg uploadedImageFile={classModalFile}
                                           onClose={() => {
                                             this.setState({ classModalVisible: false });
                                           }}
                                           onSubmit={this.handleGetResultImgUrl('classResultImgUrl')}/>)}
      </div>
    );

  }
}

 

在Vue 3中,使用`this.$refs`来引用组件的方式已经被废弃了。取而代之的是使用`ref`函数来创建一个引用,并通过`.value`来访问引用的组件实例。所以在Vue 3中,你可以通过以下方式来实现`this.$refs.cropper`的功能: 1. 在模板中使用`ref`函数创建一个引用: ```html <vue-cropper ref="cropper"></vue-cropper> ``` 2. 在组件的`setup`函数中使用`ref`函数创建一个引用,并将其返回: ```javascript import { ref } from 'vue'; export default { setup() { const cropperRef = ref(null); return { cropperRef }; } } ``` 3. 在需要使用`this.$refs.cropper`的地方,使用`cropperRef.value`来访问引用的组件实例: ```javascript // 开始截图 cropperRef.value.startCrop(); // 停止截图 cropperRef.value.stopCrop(); // 清除截图 cropperRef.value.clearCrop(); // 修改图片大小 cropperRef.value.changeScale(); // 获取图片基于容器的坐标点 cropperRef.value.getImgAxis(); // 获取截图框基于容器的坐标点 cropperRef.value.getCropAxis(); // 自动生成截图框函数 cropperRef.value.goAutoCrop(); // 向右边旋转90度 cropperRef.value.rotateRight(); // 向左边旋转90度 cropperRef.value.rotateLeft(); // 获取截图框宽度 const cropWidth = cropperRef.value.cropW; // 获取截图框高度 const cropHeight = cropperRef.value.cropH; ``` 通过以上步骤,你可以在Vue 3中实现与`this.$refs.cropper`相同的功能。 #### 引用[.reference_title] - *1* *2* *3* [vue+图片裁剪vue-cropper以及api](https://blog.csdn.net/qq_41619796/article/details/103617899)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值