123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779 |
- <template>
- <div v-show="value" class="vue-image-crop-upload">
- <div class="vicp-wrap">
- <div class="vicp-close" @click="off">
- <i class="vicp-icon4" />
- </div>
- <div v-show="step == 1" class="vicp-step1">
- <div
- class="vicp-drop-area"
- @dragleave="preventDefault"
- @dragover="preventDefault"
- @dragenter="preventDefault"
- @click="handleClick"
- @drop="handleChange"
- >
- <i v-show="loading != 1" class="vicp-icon1">
- <i class="vicp-icon1-arrow" />
- <i class="vicp-icon1-body" />
- <i class="vicp-icon1-bottom" />
- </i>
- <span v-show="loading !== 1" class="vicp-hint">{{ lang.hint }}</span>
- <span v-show="!isSupported" class="vicp-no-supported-hint">{{ lang.noSupported }}</span>
- <input v-show="false" v-if="step == 1" ref="fileinput" type="file" @change="handleChange">
- </div>
- <div v-show="hasError" class="vicp-error">
- <i class="vicp-icon2" />
- {{ errorMsg }}
- </div>
- <div class="vicp-operate">
- <a @click="off" @mousedown="ripple">{{ lang.btn.off }}</a>
- </div>
- </div>
- <div v-if="step == 2" class="vicp-step2">
- <div class="vicp-crop">
- <div v-show="true" class="vicp-crop-left">
- <div class="vicp-img-container">
- <img
- ref="img"
- :src="sourceImgUrl"
- :style="sourceImgStyle"
- class="vicp-img"
- draggable="false"
- @drag="preventDefault"
- @dragstart="preventDefault"
- @dragend="preventDefault"
- @dragleave="preventDefault"
- @dragover="preventDefault"
- @dragenter="preventDefault"
- @drop="preventDefault"
- @touchstart="imgStartMove"
- @touchmove="imgMove"
- @touchend="createImg"
- @touchcancel="createImg"
- @mousedown="imgStartMove"
- @mousemove="imgMove"
- @mouseup="createImg"
- @mouseout="createImg"
- >
- <div :style="sourceImgShadeStyle" class="vicp-img-shade vicp-img-shade-1" />
- <div :style="sourceImgShadeStyle" class="vicp-img-shade vicp-img-shade-2" />
- </div>
- <div class="vicp-range">
- <input
- :value="scale.range"
- type="range"
- step="1"
- min="0"
- max="100"
- @input="zoomChange"
- >
- <i
- class="vicp-icon5"
- @mousedown="startZoomSub"
- @mouseout="endZoomSub"
- @mouseup="endZoomSub"
- />
- <i
- class="vicp-icon6"
- @mousedown="startZoomAdd"
- @mouseout="endZoomAdd"
- @mouseup="endZoomAdd"
- />
- </div>
- <div v-if="!noRotate" class="vicp-rotate">
- <i @mousedown="startRotateLeft" @mouseout="endRotate" @mouseup="endRotate">↺</i>
- <i @mousedown="startRotateRight" @mouseout="endRotate" @mouseup="endRotate">↻</i>
- </div>
- </div>
- <div v-show="true" class="vicp-crop-right">
- <div class="vicp-preview">
- <div v-if="!noSquare" class="vicp-preview-item">
- <img :src="createImgUrl" :style="previewStyle">
- <span>{{ lang.preview }}</span>
- </div>
- <div v-if="!noCircle" class="vicp-preview-item vicp-preview-item-circle">
- <img :src="createImgUrl" :style="previewStyle">
- <span>{{ lang.preview }}</span>
- </div>
- </div>
- </div>
- </div>
- <div class="vicp-operate">
- <a @click="setStep(1)" @mousedown="ripple">{{ lang.btn.back }}</a>
- <a class="vicp-operate-btn" @click="prepareUpload" @mousedown="ripple">{{ lang.btn.save }}</a>
- </div>
- </div>
- <div v-if="step == 3" class="vicp-step3">
- <div class="vicp-upload">
- <span v-show="loading === 1" class="vicp-loading">{{ lang.loading }}</span>
- <div class="vicp-progress-wrap">
- <span v-show="loading === 1" :style="progressStyle" class="vicp-progress" />
- </div>
- <div v-show="hasError" class="vicp-error">
- <i class="vicp-icon2" />
- {{ errorMsg }}
- </div>
- <div v-show="loading === 2" class="vicp-success">
- <i class="vicp-icon3" />
- {{ lang.success }}
- </div>
- </div>
- <div class="vicp-operate">
- <a @click="setStep(2)" @mousedown="ripple">{{ lang.btn.back }}</a>
- <a @click="off" @mousedown="ripple">{{ lang.btn.close }}</a>
- </div>
- </div>
- <canvas v-show="false" ref="canvas" :width="width" :height="height" />
- </div>
- </div>
- </template>
- <script>
- 'use strict'
- import request from '@/utils/request'
- import language from './utils/language.js'
- import mimes from './utils/mimes.js'
- import data2blob from './utils/data2blob.js'
- import effectRipple from './utils/effectRipple.js'
- export default {
- props: {
- // 域,上传文件name,触发事件会带上(如果一个页面多个图片上传控件,可以做区分
- field: {
- type: String,
- default: 'avatar'
- },
- // 原名key,类似于id,触发事件会带上(如果一个页面多个图片上传控件,可以做区分
- ki: {
- type: Number,
- default: 0
- },
- // 显示该控件与否
- value: {
- type: Boolean,
- default: true
- },
- // 上传地址
- url: {
- type: String,
- default: ''
- },
- // 其他要上传文件附带的数据,对象格式
- params: {
- type: Object,
- default: null
- },
- // Add custom headers
- headers: {
- type: Object,
- default: null
- },
- // 剪裁图片的宽
- width: {
- type: Number,
- default: 200
- },
- // 剪裁图片的高
- height: {
- type: Number,
- default: 200
- },
- // 不显示旋转功能
- noRotate: {
- type: Boolean,
- default: true
- },
- // 不预览圆形图片
- noCircle: {
- type: Boolean,
- default: false
- },
- // 不预览方形图片
- noSquare: {
- type: Boolean,
- default: false
- },
- // 单文件大小限制
- maxSize: {
- type: Number,
- default: 10240
- },
- // 语言类型
- langType: {
- type: String,
- default: 'zh'
- },
- // 语言包
- langExt: {
- type: Object,
- default: null
- },
- // 图片上传格式
- imgFormat: {
- type: String,
- default: 'png'
- },
- // 是否支持跨域
- withCredentials: {
- type: Boolean,
- default: false
- }
- },
- data() {
- const { imgFormat, langType, langExt, width, height } = this
- let isSupported = true
- const allowImgFormat = ['jpg', 'png']
- const tempImgFormat =
- allowImgFormat.indexOf(imgFormat) === -1 ? 'jpg' : imgFormat
- const lang = language[langType] ? language[langType] : language['en']
- const mime = mimes[tempImgFormat]
- // 规范图片格式
- this.imgFormat = tempImgFormat
- if (langExt) {
- Object.assign(lang, langExt)
- }
- if (typeof FormData !== 'function') {
- isSupported = false
- }
- return {
- // 图片的mime
- mime,
- // 语言包
- lang,
- // 浏览器是否支持该控件
- isSupported,
- // 浏览器是否支持触屏事件
- // eslint-disable-next-line no-prototype-builtins
- isSupportTouch: document.hasOwnProperty('ontouchstart'),
- // 步骤
- step: 1, // 1选择文件 2剪裁 3上传
- // 上传状态及进度
- loading: 0, // 0未开始 1正在 2成功 3错误
- progress: 0,
- // 是否有错误及错误信息
- hasError: false,
- errorMsg: '',
- // 需求图宽高比
- ratio: width / height,
- // 原图地址、生成图片地址
- sourceImg: null,
- sourceImgUrl: '',
- createImgUrl: '',
- // 原图片拖动事件初始值
- sourceImgMouseDown: {
- on: false,
- mX: 0, // 鼠标按下的坐标
- mY: 0,
- x: 0, // scale原图坐标
- y: 0
- },
- // 生成图片预览的容器大小
- previewContainer: {
- width: 100,
- height: 100
- },
- // 原图容器宽高
- sourceImgContainer: {
- // sic
- width: 240,
- height: 184 // 如果生成图比例与此一致会出现bug,先改成特殊的格式吧,哈哈哈
- },
- // 原图展示属性
- scale: {
- zoomAddOn: false, // 按钮缩放事件开启
- zoomSubOn: false, // 按钮缩放事件开启
- range: 1, // 最大100
- rotateLeft: false, // 按钮向左旋转事件开启
- rotateRight: false, // 按钮向右旋转事件开启
- degree: 0, // 旋转度数
- x: 0,
- y: 0,
- width: 0,
- height: 0,
- maxWidth: 0,
- maxHeight: 0,
- minWidth: 0, // 最宽
- minHeight: 0,
- naturalWidth: 0, // 原宽
- naturalHeight: 0
- }
- }
- },
- computed: {
- // 进度条样式
- progressStyle() {
- const { progress } = this
- return {
- width: progress + '%'
- }
- },
- // 原图样式
- sourceImgStyle() {
- const { scale, sourceImgMasking } = this
- const top = scale.y + sourceImgMasking.y + 'px'
- const left = scale.x + sourceImgMasking.x + 'px'
- return {
- top,
- left,
- width: scale.width + 'px',
- height: scale.height + 'px',
- transform: 'rotate(' + scale.degree + 'deg)', // 旋转时 左侧原始图旋转样式
- '-ms-transform': 'rotate(' + scale.degree + 'deg)', // 兼容IE9
- '-moz-transform': 'rotate(' + scale.degree + 'deg)', // 兼容FireFox
- '-webkit-transform': 'rotate(' + scale.degree + 'deg)', // 兼容Safari 和 chrome
- '-o-transform': 'rotate(' + scale.degree + 'deg)' // 兼容 Opera
- }
- },
- // 原图蒙版属性
- sourceImgMasking() {
- const { width, height, ratio, sourceImgContainer } = this
- const sic = sourceImgContainer
- const sicRatio = sic.width / sic.height // 原图容器宽高比
- let x = 0
- let y = 0
- let w = sic.width
- let h = sic.height
- let scale = 1
- if (ratio < sicRatio) {
- scale = sic.height / height
- w = sic.height * ratio
- x = (sic.width - w) / 2
- }
- if (ratio > sicRatio) {
- scale = sic.width / width
- h = sic.width / ratio
- y = (sic.height - h) / 2
- }
- return {
- scale, // 蒙版相对需求宽高的缩放
- x,
- y,
- width: w,
- height: h
- }
- },
- // 原图遮罩样式
- sourceImgShadeStyle() {
- const { sourceImgMasking, sourceImgContainer } = this
- const sic = sourceImgContainer
- const sim = sourceImgMasking
- const w =
- sim.width === sic.width ? sim.width : (sic.width - sim.width) / 2
- const h =
- sim.height === sic.height ? sim.height : (sic.height - sim.height) / 2
- return {
- width: w + 'px',
- height: h + 'px'
- }
- },
- previewStyle() {
- const { ratio, previewContainer } = this
- const pc = previewContainer
- let w = pc.width
- let h = pc.height
- const pcRatio = w / h
- if (ratio < pcRatio) {
- w = pc.height * ratio
- }
- if (ratio > pcRatio) {
- h = pc.width / ratio
- }
- return {
- width: w + 'px',
- height: h + 'px'
- }
- }
- },
- watch: {
- value(newValue) {
- if (newValue && this.loading !== 1) {
- this.reset()
- }
- }
- },
- created() {
- // 绑定按键esc隐藏此插件事件
- document.addEventListener('keyup', this.closeHandler)
- },
- destroyed() {
- document.removeEventListener('keyup', this.closeHandler)
- },
- methods: {
- // 点击波纹效果
- ripple(e) {
- effectRipple(e)
- },
- // 关闭控件
- off() {
- setTimeout(() => {
- this.$emit('input', false)
- this.$emit('close')
- if (this.step === 3 && this.loading === 2) {
- this.setStep(1)
- }
- }, 200)
- },
- // 设置步骤
- setStep(no) {
- // 延时是为了显示动画效果呢,哈哈哈
- setTimeout(() => {
- this.step = no
- }, 200)
- },
- /* 图片选择区域函数绑定
- ---------------------------------------------------------------*/
- preventDefault(e) {
- e.preventDefault()
- return false
- },
- handleClick(e) {
- if (this.loading !== 1) {
- if (e.target !== this.$refs.fileinput) {
- e.preventDefault()
- if (document.activeElement !== this.$refs) {
- this.$refs.fileinput.click()
- }
- }
- }
- },
- handleChange(e) {
- e.preventDefault()
- if (this.loading !== 1) {
- const files = e.target.files || e.dataTransfer.files
- this.reset()
- if (this.checkFile(files[0])) {
- this.setSourceImg(files[0])
- }
- }
- },
- /* ---------------------------------------------------------------*/
- // 检测选择的文件是否合适
- checkFile(file) {
- const { lang, maxSize } = this
- // 仅限图片
- if (file.type.indexOf('image') === -1) {
- this.hasError = true
- this.errorMsg = lang.error.onlyImg
- return false
- }
- // 超出大小
- if (file.size / 1024 > maxSize) {
- this.hasError = true
- this.errorMsg = lang.error.outOfSize + maxSize + 'kb'
- return false
- }
- return true
- },
- // 重置控件
- reset() {
- this.loading = 0
- this.hasError = false
- this.errorMsg = ''
- this.progress = 0
- },
- // 设置图片源
- setSourceImg(file) {
- const fr = new FileReader()
- fr.onload = e => {
- this.sourceImgUrl = fr.result
- this.startCrop()
- }
- fr.readAsDataURL(file)
- },
- // 剪裁前准备工作
- startCrop() {
- const {
- width,
- height,
- ratio,
- scale,
- sourceImgUrl,
- sourceImgMasking,
- lang
- } = this
- const sim = sourceImgMasking
- const img = new Image()
- img.src = sourceImgUrl
- img.onload = () => {
- const nWidth = img.naturalWidth
- const nHeight = img.naturalHeight
- const nRatio = nWidth / nHeight
- let w = sim.width
- let h = sim.height
- let x = 0
- let y = 0
- // 图片像素不达标
- if (nWidth < width || nHeight < height) {
- this.hasError = true
- this.errorMsg = lang.error.lowestPx + width + '*' + height
- return false
- }
- if (ratio > nRatio) {
- h = w / nRatio
- y = (sim.height - h) / 2
- }
- if (ratio < nRatio) {
- w = h * nRatio
- x = (sim.width - w) / 2
- }
- scale.range = 0
- scale.x = x
- scale.y = y
- scale.width = w
- scale.height = h
- scale.degree = 0
- scale.minWidth = w
- scale.minHeight = h
- scale.maxWidth = nWidth * sim.scale
- scale.maxHeight = nHeight * sim.scale
- scale.naturalWidth = nWidth
- scale.naturalHeight = nHeight
- this.sourceImg = img
- this.createImg()
- this.setStep(2)
- }
- },
- // 鼠标按下图片准备移动
- imgStartMove(e) {
- e.preventDefault()
- // 支持触摸事件,则鼠标事件无效
- if (this.isSupportTouch && !e.targetTouches) {
- return false
- }
- const et = e.targetTouches ? e.targetTouches[0] : e
- const { sourceImgMouseDown, scale } = this
- const simd = sourceImgMouseDown
- simd.mX = et.screenX
- simd.mY = et.screenY
- simd.x = scale.x
- simd.y = scale.y
- simd.on = true
- },
- // 鼠标按下状态下移动,图片移动
- imgMove(e) {
- e.preventDefault()
- // 支持触摸事件,则鼠标事件无效
- if (this.isSupportTouch && !e.targetTouches) {
- return false
- }
- const et = e.targetTouches ? e.targetTouches[0] : e
- const {
- sourceImgMouseDown: { on, mX, mY, x, y },
- scale,
- sourceImgMasking
- } = this
- const sim = sourceImgMasking
- const nX = et.screenX
- const nY = et.screenY
- const dX = nX - mX
- const dY = nY - mY
- let rX = x + dX
- let rY = y + dY
- if (!on) return
- if (rX > 0) {
- rX = 0
- }
- if (rY > 0) {
- rY = 0
- }
- if (rX < sim.width - scale.width) {
- rX = sim.width - scale.width
- }
- if (rY < sim.height - scale.height) {
- rY = sim.height - scale.height
- }
- scale.x = rX
- scale.y = rY
- },
- // 按钮按下开始向右旋转
- startRotateRight(e) {
- const { scale } = this
- scale.rotateRight = true
- const rotate = () => {
- if (scale.rotateRight) {
- const degree = ++scale.degree
- this.createImg(degree)
- setTimeout(function() {
- rotate()
- }, 60)
- }
- }
- rotate()
- },
- // 按钮按下开始向左旋转
- startRotateLeft(e) {
- const { scale } = this
- scale.rotateLeft = true
- const rotate = () => {
- if (scale.rotateLeft) {
- const degree = --scale.degree
- this.createImg(degree)
- setTimeout(function() {
- rotate()
- }, 60)
- }
- }
- rotate()
- },
- // 停止旋转
- endRotate() {
- const { scale } = this
- scale.rotateLeft = false
- scale.rotateRight = false
- },
- // 按钮按下开始放大
- startZoomAdd(e) {
- const { scale } = this
- scale.zoomAddOn = true
- const zoom = () => {
- if (scale.zoomAddOn) {
- const range = scale.range >= 100 ? 100 : ++scale.range
- this.zoomImg(range)
- setTimeout(function() {
- zoom()
- }, 60)
- }
- }
- zoom()
- },
- // 按钮松开或移开取消放大
- endZoomAdd(e) {
- this.scale.zoomAddOn = false
- },
- // 按钮按下开始缩小
- startZoomSub(e) {
- const { scale } = this
- scale.zoomSubOn = true
- const zoom = () => {
- if (scale.zoomSubOn) {
- const range = scale.range <= 0 ? 0 : --scale.range
- this.zoomImg(range)
- setTimeout(function() {
- zoom()
- }, 60)
- }
- }
- zoom()
- },
- // 按钮松开或移开取消缩小
- endZoomSub(e) {
- const { scale } = this
- scale.zoomSubOn = false
- },
- zoomChange(e) {
- this.zoomImg(e.target.value)
- },
- // 缩放原图
- zoomImg(newRange) {
- const { sourceImgMasking, scale } = this
- const {
- maxWidth,
- maxHeight,
- minWidth,
- minHeight,
- width,
- height,
- x,
- y
- } = scale
- const sim = sourceImgMasking
- // 蒙版宽高
- const sWidth = sim.width
- const sHeight = sim.height
- // 新宽高
- const nWidth = minWidth + ((maxWidth - minWidth) * newRange) / 100
- const nHeight = minHeight + ((maxHeight - minHeight) * newRange) / 100
- // 新坐标(根据蒙版中心点缩放)
- let nX = sWidth / 2 - (nWidth / width) * (sWidth / 2 - x)
- let nY = sHeight / 2 - (nHeight / height) * (sHeight / 2 - y)
- // 判断新坐标是否超过蒙版限制
- if (nX > 0) {
- nX = 0
- }
- if (nY > 0) {
- nY = 0
- }
- if (nX < sWidth - nWidth) {
- nX = sWidth - nWidth
- }
- if (nY < sHeight - nHeight) {
- nY = sHeight - nHeight
- }
- // 赋值处理
- scale.x = nX
- scale.y = nY
- scale.width = nWidth
- scale.height = nHeight
- scale.range = newRange
- setTimeout(() => {
- if (scale.range === newRange) {
- this.createImg()
- }
- }, 300)
- },
- // 生成需求图片
- createImg(e) {
- const {
- mime,
- sourceImg,
- scale: { x, y, width, height, degree },
- sourceImgMasking: { scale }
- } = this
- const canvas = this.$refs.canvas
- const ctx = canvas.getContext('2d')
- if (e) {
- // 取消鼠标按下移动状态
- this.sourceImgMouseDown.on = false
- }
- canvas.width = this.width
- canvas.height = this.height
- ctx.clearRect(0, 0, this.width, this.height)
- // 将透明区域设置为白色底边
- ctx.fillStyle = '#fff'
- ctx.fillRect(0, 0, this.width, this.height)
- ctx.translate(this.width * 0.5, this.height * 0.5)
- ctx.rotate((Math.PI * degree) / 180)
- ctx.translate(-this.width * 0.5, -this.height * 0.5)
- ctx.drawImage(
- sourceImg,
- x / scale,
- y / scale,
- width / scale,
- height / scale
- )
- this.createImgUrl = canvas.toDataURL(mime)
- },
- prepareUpload() {
- const { url, createImgUrl, field, ki } = this
- this.$emit('crop-success', createImgUrl, field, ki)
- if (typeof url === 'string' && url) {
- this.upload()
- } else {
- this.off()
- }
- },
- // 上传图片
- upload() {
- const {
- lang,
- imgFormat,
- mime,
- url,
- params,
- field,
- ki,
- createImgUrl
- } = this
- const fmData = new FormData()
- fmData.append(
- field,
- data2blob(createImgUrl, mime),
- field + '.' + imgFormat
- )
- // 添加其他参数
- if (typeof params === 'object' && params) {
- Object.keys(params).forEach(k => {
- fmData.append(k, params[k])
- })
- }
- // 监听进度回调
- // const uploadProgress = (event) => {
- // if (event.lengthComputable) {
- // this.progress = 100 * Math.round(event.loaded) / event.total
- // }
- // }
- // 上传文件
- this.reset()
- this.loading = 1
- this.setStep(3)
- request({
- url,
- method: 'post',
- data: fmData
- })
- .then(resData => {
- this.loading = 2
- this.$emit('crop-upload-success', resData.data)
- })
- .catch(err => {
- if (this.value) {
- this.loading = 3
- this.hasError = true
- this.errorMsg = lang.fail
- this.$emit('crop-upload-fail', err, field, ki)
- }
- })
- },
- closeHandler(e) {
- if (this.value && (e.key === 'Escape' || e.keyCode === 27)) {
- this.off()
- }
- }
- }
- }
- </script>
- <style lang="scss">
- @charset "UTF-8";
- @-webkit-keyframes vicp_progress {
- 0% {
- background-position-y: 0;
- }
- 100% {
- background-position-y: 40px;
- }
- }
- @keyframes vicp_progress {
- 0% {
- background-position-y: 0;
- }
- 100% {
- background-position-y: 40px;
- }
- }
- @-webkit-keyframes vicp {
- 0% {
- opacity: 0;
- -webkit-transform: scale(0) translatey(-60px);
- transform: scale(0) translatey(-60px);
- }
- 100% {
- opacity: 1;
- -webkit-transform: scale(1) translatey(0);
- transform: scale(1) translatey(0);
- }
- }
- @keyframes vicp {
- 0% {
- opacity: 0;
- -webkit-transform: scale(0) translatey(-60px);
- transform: scale(0) translatey(-60px);
- }
- 100% {
- opacity: 1;
- -webkit-transform: scale(1) translatey(0);
- transform: scale(1) translatey(0);
- }
- }
- .vue-image-crop-upload {
- position: fixed;
- display: block;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- z-index: 10000;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.65);
- -webkit-tap-highlight-color: transparent;
- -moz-tap-highlight-color: transparent;
- }
- .vue-image-crop-upload .vicp-wrap {
- -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- position: fixed;
- display: block;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- z-index: 10000;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- margin: auto;
- width: 600px;
- height: 330px;
- padding: 25px;
- background-color: #fff;
- border-radius: 2px;
- -webkit-animation: vicp 0.12s ease-in;
- animation: vicp 0.12s ease-in;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-close {
- position: absolute;
- right: -30px;
- top: -30px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4 {
- position: relative;
- display: block;
- width: 30px;
- height: 30px;
- cursor: pointer;
- -webkit-transition: -webkit-transform 0.18s;
- transition: -webkit-transform 0.18s;
- transition: transform 0.18s;
- transition: transform 0.18s, -webkit-transform 0.18s;
- -webkit-transform: rotate(0);
- -ms-transform: rotate(0);
- transform: rotate(0);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after,
- .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::before {
- -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- content: "";
- position: absolute;
- top: 12px;
- left: 4px;
- width: 20px;
- height: 3px;
- -webkit-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- transform: rotate(45deg);
- background-color: #fff;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after {
- -webkit-transform: rotate(-45deg);
- -ms-transform: rotate(-45deg);
- transform: rotate(-45deg);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4:hover {
- -webkit-transform: rotate(90deg);
- -ms-transform: rotate(90deg);
- transform: rotate(90deg);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area {
- position: relative;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- padding: 35px;
- height: 170px;
- background-color: rgba(0, 0, 0, 0.03);
- text-align: center;
- border: 1px dashed rgba(0, 0, 0, 0.08);
- overflow: hidden;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 {
- display: block;
- margin: 0 auto 6px;
- width: 42px;
- height: 42px;
- overflow: hidden;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step1
- .vicp-drop-area
- .vicp-icon1
- .vicp-icon1-arrow {
- display: block;
- margin: 0 auto;
- width: 0;
- height: 0;
- border-bottom: 14.7px solid rgba(0, 0, 0, 0.3);
- border-left: 14.7px solid transparent;
- border-right: 14.7px solid transparent;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step1
- .vicp-drop-area
- .vicp-icon1
- .vicp-icon1-body {
- display: block;
- width: 12.6px;
- height: 14.7px;
- margin: 0 auto;
- background-color: rgba(0, 0, 0, 0.3);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step1
- .vicp-drop-area
- .vicp-icon1
- .vicp-icon1-bottom {
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- display: block;
- height: 12.6px;
- border: 6px solid rgba(0, 0, 0, 0.3);
- border-top: none;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-hint {
- display: block;
- padding: 15px;
- font-size: 14px;
- color: #666;
- line-height: 30px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step1
- .vicp-drop-area
- .vicp-no-supported-hint {
- display: block;
- position: absolute;
- top: 0;
- left: 0;
- padding: 30px;
- width: 100%;
- height: 60px;
- line-height: 30px;
- background-color: #eee;
- text-align: center;
- color: #666;
- font-size: 14px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area:hover {
- cursor: pointer;
- border-color: rgba(0, 0, 0, 0.1);
- background-color: rgba(0, 0, 0, 0.05);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop {
- overflow: hidden;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left {
- float: left;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-img-container {
- position: relative;
- display: block;
- width: 240px;
- height: 180px;
- background-color: #e5e5e0;
- overflow: hidden;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-img-container
- .vicp-img {
- position: absolute;
- display: block;
- cursor: move;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-img-container
- .vicp-img-shade {
- -webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
- box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
- position: absolute;
- background-color: rgba(241, 242, 243, 0.8);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-img-container
- .vicp-img-shade.vicp-img-shade-1 {
- top: 0;
- left: 0;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-img-container
- .vicp-img-shade.vicp-img-shade-2 {
- bottom: 0;
- right: 0;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-rotate {
- position: relative;
- width: 240px;
- height: 18px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-rotate
- i {
- display: block;
- width: 18px;
- height: 18px;
- border-radius: 100%;
- line-height: 18px;
- text-align: center;
- font-size: 12px;
- font-weight: bold;
- background-color: rgba(0, 0, 0, 0.08);
- color: #fff;
- overflow: hidden;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-rotate
- i:hover {
- -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- cursor: pointer;
- background-color: rgba(0, 0, 0, 0.14);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-rotate
- i:first-child {
- float: left;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-rotate
- i:last-child {
- float: right;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range {
- position: relative;
- margin: 30px 0 10px 0;
- width: 240px;
- height: 18px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon5,
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon6 {
- position: absolute;
- top: 0;
- width: 18px;
- height: 18px;
- border-radius: 100%;
- background-color: rgba(0, 0, 0, 0.08);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon5:hover,
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon6:hover {
- -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- cursor: pointer;
- background-color: rgba(0, 0, 0, 0.14);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon5 {
- left: 0;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon5::before {
- position: absolute;
- content: "";
- display: block;
- left: 3px;
- top: 8px;
- width: 12px;
- height: 2px;
- background-color: #fff;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon6 {
- right: 0;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon6::before {
- position: absolute;
- content: "";
- display: block;
- left: 3px;
- top: 8px;
- width: 12px;
- height: 2px;
- background-color: #fff;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- .vicp-icon6::after {
- position: absolute;
- content: "";
- display: block;
- top: 3px;
- left: 8px;
- width: 2px;
- height: 12px;
- background-color: #fff;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"] {
- display: block;
- padding-top: 5px;
- margin: 0 auto;
- width: 180px;
- height: 8px;
- vertical-align: top;
- background: transparent;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- cursor: pointer;
- /* 滑块
- ---------------------------------------------------------------*/
- /* 轨道
- ---------------------------------------------------------------*/
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:focus {
- outline: none;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-webkit-slider-thumb {
- -webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
- box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
- -webkit-appearance: none;
- appearance: none;
- margin-top: -3px;
- width: 12px;
- height: 12px;
- background-color: #61c091;
- border-radius: 100%;
- border: none;
- -webkit-transition: 0.2s;
- transition: 0.2s;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-moz-range-thumb {
- box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
- -moz-appearance: none;
- appearance: none;
- width: 12px;
- height: 12px;
- background-color: #61c091;
- border-radius: 100%;
- border: none;
- -webkit-transition: 0.2s;
- transition: 0.2s;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-ms-thumb {
- box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
- appearance: none;
- width: 12px;
- height: 12px;
- background-color: #61c091;
- border: none;
- border-radius: 100%;
- -webkit-transition: 0.2s;
- transition: 0.2s;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:active::-moz-range-thumb {
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- width: 14px;
- height: 14px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:active::-ms-thumb {
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- width: 14px;
- height: 14px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:active::-webkit-slider-thumb {
- -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
- margin-top: -4px;
- width: 14px;
- height: 14px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-webkit-slider-runnable-track {
- -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- width: 100%;
- height: 6px;
- cursor: pointer;
- border-radius: 2px;
- border: none;
- background-color: rgba(68, 170, 119, 0.3);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-moz-range-track {
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- width: 100%;
- height: 6px;
- cursor: pointer;
- border-radius: 2px;
- border: none;
- background-color: rgba(68, 170, 119, 0.3);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-ms-track {
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
- width: 100%;
- cursor: pointer;
- background: transparent;
- border-color: transparent;
- color: transparent;
- height: 6px;
- border-radius: 2px;
- border: none;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-ms-fill-lower {
- background-color: rgba(68, 170, 119, 0.3);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]::-ms-fill-upper {
- background-color: rgba(68, 170, 119, 0.15);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:focus::-webkit-slider-runnable-track {
- background-color: rgba(68, 170, 119, 0.5);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:focus::-moz-range-track {
- background-color: rgba(68, 170, 119, 0.5);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:focus::-ms-fill-lower {
- background-color: rgba(68, 170, 119, 0.45);
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-left
- .vicp-range
- input[type="range"]:focus::-ms-fill-upper {
- background-color: rgba(68, 170, 119, 0.25);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right {
- float: right;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-right
- .vicp-preview {
- height: 150px;
- overflow: hidden;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-right
- .vicp-preview
- .vicp-preview-item {
- position: relative;
- padding: 5px;
- width: 100px;
- height: 100px;
- float: left;
- margin-right: 16px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-right
- .vicp-preview
- .vicp-preview-item
- span {
- position: absolute;
- bottom: -30px;
- width: 100%;
- font-size: 14px;
- color: #bbb;
- display: block;
- text-align: center;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-right
- .vicp-preview
- .vicp-preview-item
- img {
- position: absolute;
- display: block;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- margin: auto;
- padding: 3px;
- background-color: #fff;
- border: 1px solid rgba(0, 0, 0, 0.15);
- overflow: hidden;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-right
- .vicp-preview
- .vicp-preview-item.vicp-preview-item-circle {
- margin-right: 0;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step2
- .vicp-crop
- .vicp-crop-right
- .vicp-preview
- .vicp-preview-item.vicp-preview-item-circle
- img {
- border-radius: 100%;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload {
- position: relative;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- padding: 35px;
- height: 170px;
- background-color: rgba(0, 0, 0, 0.03);
- text-align: center;
- border: 1px dashed #ddd;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-loading {
- display: block;
- padding: 15px;
- font-size: 16px;
- color: #999;
- line-height: 30px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap {
- margin-top: 12px;
- background-color: rgba(0, 0, 0, 0.08);
- border-radius: 3px;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step3
- .vicp-upload
- .vicp-progress-wrap
- .vicp-progress {
- position: relative;
- display: block;
- height: 5px;
- border-radius: 3px;
- background-color: #4a7;
- -webkit-box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
- box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
- -webkit-transition: width 0.15s linear;
- transition: width 0.15s linear;
- background-image: -webkit-linear-gradient(
- 135deg,
- rgba(255, 255, 255, 0.2) 25%,
- transparent 25%,
- transparent 50%,
- rgba(255, 255, 255, 0.2) 50%,
- rgba(255, 255, 255, 0.2) 75%,
- transparent 75%,
- transparent
- );
- background-image: linear-gradient(
- -45deg,
- rgba(255, 255, 255, 0.2) 25%,
- transparent 25%,
- transparent 50%,
- rgba(255, 255, 255, 0.2) 50%,
- rgba(255, 255, 255, 0.2) 75%,
- transparent 75%,
- transparent
- );
- background-size: 40px 40px;
- -webkit-animation: vicp_progress 0.5s linear infinite;
- animation: vicp_progress 0.5s linear infinite;
- }
- .vue-image-crop-upload
- .vicp-wrap
- .vicp-step3
- .vicp-upload
- .vicp-progress-wrap
- .vicp-progress::after {
- content: "";
- position: absolute;
- display: block;
- top: -3px;
- right: -3px;
- width: 9px;
- height: 9px;
- border: 1px solid rgba(245, 246, 247, 0.7);
- -webkit-box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
- box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
- border-radius: 100%;
- background-color: #4a7;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-error,
- .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-success {
- height: 100px;
- line-height: 100px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-operate {
- position: absolute;
- right: 20px;
- bottom: 20px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-operate a {
- position: relative;
- float: left;
- display: block;
- margin-left: 10px;
- width: 100px;
- height: 36px;
- line-height: 36px;
- text-align: center;
- cursor: pointer;
- font-size: 14px;
- color: #4a7;
- border-radius: 2px;
- overflow: hidden;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-operate a:hover {
- background-color: rgba(0, 0, 0, 0.03);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-error,
- .vue-image-crop-upload .vicp-wrap .vicp-success {
- display: block;
- font-size: 14px;
- line-height: 24px;
- height: 24px;
- color: #d10;
- text-align: center;
- vertical-align: top;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-success {
- color: #4a7;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-icon3 {
- position: relative;
- display: inline-block;
- width: 20px;
- height: 20px;
- top: 4px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-icon3::after {
- position: absolute;
- top: 3px;
- left: 6px;
- width: 6px;
- height: 10px;
- border-width: 0 2px 2px 0;
- border-color: #4a7;
- border-style: solid;
- -webkit-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- transform: rotate(45deg);
- content: "";
- }
- .vue-image-crop-upload .vicp-wrap .vicp-icon2 {
- position: relative;
- display: inline-block;
- width: 20px;
- height: 20px;
- top: 4px;
- }
- .vue-image-crop-upload .vicp-wrap .vicp-icon2::after,
- .vue-image-crop-upload .vicp-wrap .vicp-icon2::before {
- content: "";
- position: absolute;
- top: 9px;
- left: 4px;
- width: 13px;
- height: 2px;
- background-color: #d10;
- -webkit-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- transform: rotate(45deg);
- }
- .vue-image-crop-upload .vicp-wrap .vicp-icon2::after {
- -webkit-transform: rotate(-45deg);
- -ms-transform: rotate(-45deg);
- transform: rotate(-45deg);
- }
- .e-ripple {
- position: absolute;
- border-radius: 100%;
- background-color: rgba(0, 0, 0, 0.15);
- background-clip: padding-box;
- pointer-events: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-transform: scale(0);
- -ms-transform: scale(0);
- transform: scale(0);
- opacity: 1;
- }
- .e-ripple.z-active {
- opacity: 0;
- -webkit-transform: scale(2);
- -ms-transform: scale(2);
- transform: scale(2);
- -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
- transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
- transition: opacity 1.2s ease-out, transform 0.6s ease-out;
- transition: opacity 1.2s ease-out, transform 0.6s ease-out,
- -webkit-transform 0.6s ease-out;
- }
- </style>
|