import styles from './index.less'import { PureComponent, createRef } from 'react'import QRCode from 'qrcode'import html2canvas from 'html2canvas'import classnames from 'classnames'import preventScroll from 'prevent-scroll'import growingService from '@xb/services/growing'import MaskBasic from '@xb/components/Mask/Basic'import MaskCenter from '@xb/components/Mask/Center'import ButtonBasic from '@xb/components/Button/Basic'import Line from '@xb/components/Line/Basic'import { MountPoint, sleep } from '@xb/utils/dom'import { device } from '@xb/utils/userAgent'import creditService from '@xb/services/credit'import iconLogoComplete from '@xb/assets/icons/icon-logo-complete.png'import ellipseBg from '@xb/assets/ellipse-bg.png'import userImg from '@xb/assets/user.png'class ModalComponent extends PureComponent { constructor(props) { super(props) const { onClick, uniqueId, noteId } = this.props this.onClick = onClick this.node = createRef() this.container = createRef() this.saveImage = createRef() this.avatar = createRef() this.startTime = '' this.endTime = '' const link = `${window.location.origin}/course/note/landing/${uniqueId}/${noteId}?sourceType=h5wxshare` this.action.generateQR(link) this.state = { once: true, qrcode: false, } } action = { generateQR: async url => { try { const baseImage = await QRCode.toDataURL(url) const image = new Image() image.src = baseImage this.node.current.appendChild(image) this.setState({ qrcode: true }) } catch (err) { console.error(err) } }, generateImage: async () => { const canvas = this.action.drawCanvas(this.container.current) await sleep(300) html2canvas(this.container.current, { useCORS: true, logging: false, canvas, scale: 10, letterRendering: true, }).then(canvas => { const image = new Image() image.src = canvas.toDataURL('image/png') this.saveImage.current.appendChild(image) }) }, checkPicture: async url => { return new Promise(resolve => { const image = new Image() image.src = url image.onload = () => { resolve(url) } image.onerror = () => { resolve(userImg) } }) }, DPR: () => { if (window.devicePixelRatio && window.devicePixelRatio > 1) { return window.devicePixelRatio } return 1 }, parseValue: value => { return parseInt(value, 10) }, drawCanvas: node => { const box = window.getComputedStyle(node) // DOM 节点计算后宽高 const width = this.action.parseValue(box.width) const height = this.action.parseValue(box.height) // 获取像素比 const scaleBy = this.action.DPR() // 创建自定义 canvas 元素 const canvas = document.createElement('canvas') // 设定 canvas 元素属性宽高为 DOM 节点宽高 * 像素比 canvas.width = width * scaleBy canvas.height = height * scaleBy // 设定 canvas css宽高为 DOM 节点宽高 canvas.style.width = `${width}px` canvas.style.height = `${height}px` // 获取画笔 const context = canvas.getContext('2d') // 【重要】关闭抗锯齿 context.mozImageSmoothingEnabled = false context.msImageSmoothingEnabled = false context.imageSmoothingEnabled = false // 将所有绘制内容放大像素比倍 context.scale(scaleBy, scaleBy) return canvas }, touchstart: () => { this.startTime = +new Date() }, touchend: () => { this.endTime = +new Date() const { uniqueId } = this.props if (this.endTime - this.startTime > 700) { const { payload } = this.props growingService.noteShareImage(payload) try { creditService.shareNote(uniqueId) } catch (error) { console.error(error) } } }, } render() { const { userUrl, userName, createdTime, content, productTitle } = this.props const { once, qrcode } = this.state const isIOSBox = device.isIOS ? styles.isIOSBox : '' const isIOSNote = device.isIOS ? styles.isIOSNote : '' const avatar = this.action.checkPicture(userUrl) avatar.then(url => { this.avatar.current.src = url if (once && qrcode) { this.action.generateImage() this.setState({ once: false }) } }) return ( <MaskBasic onClick={this.onClick}> <MaskCenter> <div className={classnames(styles.box, isIOSBox)} onClick={e => e.stopPropagation()}> <div ref={this.saveImage} className={styles.containerImage} onTouchStart={this.action.touchstart} onTouchEnd={this.action.touchend} /> <div ref={this.container} className={styles.container}> <img className={styles.logo} src={iconLogoComplete} /> <img className={styles.ellipse} src={ellipseBg} /> <div className={styles.content}> <div className={styles.product}> <span>来自课程</span> <p>{productTitle}</p> </div> <div className={styles.userInfo}> <img ref={this.avatar} className={styles.avatar} crossOrigin='anonymous' /> <div className={styles.user}> <h3>{userName}</h3> <p>{createdTime}</p> </div> </div> <p className={classnames(styles.note, isIOSNote)}>{content}</p> <Line className={styles.line} size={15} /> <div className={styles.qrcodeInfo}> <div className={styles.qrcode} ref={this.node} /> <div className={styles.description}> <h3>长按识别二维码</h3> <p>查看完整笔记,亦可点赞评论</p> </div> </div> </div> </div> <div className={styles.button}> <ButtonBasic style={{ width: '100%', color: '#222222', fontWeight: 400, boxShadow: 'none' }}>长按按钮分享笔记</ButtonBasic> </div> </div> <div className={styles.close} /> </MaskCenter> </MaskBasic> ) }}class GlobalModalSharePicture extends MountPoint { hide = () => { preventScroll.off() this.removeMountPoint() } show = options => { preventScroll.on() this.render(<ModalComponent onClick={this.hide} {...options} />) }}export default new GlobalModalSharePicture()