使用cropperjs替换vue-cropper

修复上传头像失败的问题

代码优化
master
toesbieya 6 years ago
parent ce2bf95904
commit eda8fd5145
  1. 5
      vue/full/package-lock.json
  2. 1
      vue/full/package.json
  3. 4
      vue/full/src/globalMethod/Verify/main.vue
  4. 10
      vue/full/src/globalMethod/Verify/style.scss
  5. 6
      vue/full/src/util/element-ui/elTree.js
  6. 2
      vue/full/src/util/observable.js
  7. 134
      vue/full/src/view/admin/userCenter/component/Avatar.vue

@ -13591,11 +13591,6 @@
"resolved": "https://registry.npmjs.org/vue-count-to/-/vue-count-to-1.0.13.tgz",
"integrity": "sha512-6R4OVBVNtQTlcbXu6SJ8ENR35M2/CdWt3Jmv57jOUM+1ojiFmjVGvZPH8DfHpMDSA+ITs+EW5V6qthADxeyYOQ=="
},
"vue-cropper": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/vue-cropper/-/vue-cropper-0.5.4.tgz",
"integrity": "sha512-9wwHOk1eHdl+nyq2fnIFDeDMjaXPh1dqfY+FdeEGU7Z/cKVOyH0pLrW0/5NH3xnRzqrU3DAQ8LjC/9/eHdvqKA=="
},
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",

@ -21,7 +21,6 @@
"socket.io-client": "^2.3.0",
"vue": "^2.6.11",
"vue-count-to": "^1.0.13",
"vue-cropper": "^0.5.4",
"vue-router": "^3.3.4",
"vuex": "^3.4.0"
},

@ -3,7 +3,7 @@
<div
v-show="visible"
class="puzzle-container"
:class="{'puzzle-shake':stat==='fail'}"
:class="{'is-error': stat === 'fail'}"
:style="`left: ${positionLeft}px;top: ${positionTop}px;`"
>
<div class="puzzle-view" :style="`width:${width}px;height:${height}px;`">
@ -32,7 +32,7 @@
<div class="slider-container">
<div class="slider-track">
<div class="slider-tip" :style="stat==='ready'?'opacity: 1':''">拖动滑块完成拼图</div>
<div class="slider-tip" :style="stat === 'ready' ? 'opacity: 1' : ''">拖动滑块完成拼图</div>
</div>
<div class="slider-btn" :style="sliderBtnStyle" @mousedown="moveStart" @touchstart="moveStart"/>
</div>

@ -57,8 +57,6 @@
padding-top: 10%;
&__icon {
/*background-size: 764.70588%;
background-position: 0 70.70218%;*/
background-image: url(./image/loading.png);
margin: 11% auto 10px;
width: 34px;
@ -197,13 +195,12 @@
}
}
}
}
.puzzle-shake {
&.is-error {
animation: shake 0.2s linear 3 both;
}
}
@keyframes shake {
@keyframes shake {
25% {
transform: translate3d(-6px, 0, 0)
}
@ -213,4 +210,5 @@
100% {
transform: translate3d(0, 0, 0)
}
}
}

@ -4,13 +4,11 @@
* @param ref el-tree实例
* @param action 'expand' | 'collapse'
* @param level 展开的节点最大深度为0时匹配全部节点
* @param func 自定义展开的函数传入一个node返回boolean优先使用
* @param func 自定义展开的函数传入(node, index)返回boolean优先使用
*/
export function expandControl(ref, action = 'expand', level = 1, func) {
const handler = function () {
if (typeof func === 'function') {
return node => func(node)
}
if (typeof func === 'function') return func
const expand = action === 'expand'
const forAll = level === 0

@ -18,7 +18,7 @@ export function createGetters(store) {
return getters
}
//设置mutation
//为Vue.observer返回的对象设置mutation
export function createMutations(store, all = false) {
const keys = Object.keys(store)
const obj = {}

@ -1,37 +1,27 @@
<template>
<abstract-dialog :loading="loading" title="上传头像" :value="value" width="50%" @close="cancel">
<div class="avatar-cropper">
<vue-cropper
ref="cropper"
:img="img"
:info="false"
autoCrop
autoCropHeight="200px"
autoCropWidth="200px"
fixedBox
full
outputType="png"
@wheel.native.prevent="scale"
/>
<abstract-dialog :loading="loading" title="上传头像" :value="value" width="50%" @close="clear">
<div class="avatar-cropper cropper-bg">
<div v-show="!img" class="avatar-cropper-bg cropper-bg" title="选择图片" @click="handleBgClick"/>
<img :src="img">
<input
ref="input"
accept="image/png, image/jpeg, image/gif, image/jpg"
type="file"
@change="chooseImage"
@change="onInputChange"
>
</div>
<template v-slot:footer>
<el-button plain size="small" @click="$refs.input.click()">选择图片</el-button>
<el-button plain size="small" @click="chooseImage">选择图片</el-button>
<el-button plain size="small" @click="closeDialog"> </el-button>
<el-button size="small" type="primary" @click="confirm"> </el-button>
<el-button :loading="loading" size="small" type="primary" @click="confirm"> </el-button>
</template>
</abstract-dialog>
</template>
<script>
import {VueCropper} from 'vue-cropper'
import AbstractDialog from '@/component/abstract/Dialog'
import dialogMixin from "@/mixin/dialogMixin"
import {elError, elSuccess} from "@/util/message"
@ -43,7 +33,7 @@ export default {
mixins: [dialogMixin],
components: {VueCropper, AbstractDialog},
components: {AbstractDialog},
props: {
value: Boolean
@ -53,31 +43,35 @@ export default {
return {
loading: false,
img: '',
name: ''
name: '',
type: ''
}
},
methods: {
//
handleBgClick() {
!this.img && this.chooseImage()
},
clear() {
this.loading = false
this.$refs.cropper.clearCrop()
this.cropper && this.cropper.destroy()
this.img && window.URL.revokeObjectURL(this.img)
this.img = ''
this.name = ''
this.type = ''
},
scale(e) {
const eventDelta = e.wheelDelta || -(e.detail || 0) * 40
this.$refs.cropper.changeScale(eventDelta / 120)
},
chooseImage(e) {
onInputChange(e) {
if (this.loading) return
this.clear()
const file = e.target.files[0]
if (!file) return
if (!file.type.includes('image')) {
return elError('请上传图片')
}
@ -87,34 +81,71 @@ export default {
}
this.name = file.name
const reader = new FileReader()
reader.onload = e => {
this.img = window.URL.createObjectURL(new Blob([e.target.result]))
this.type = file.type
this.img = window.URL.createObjectURL(file)
//使nextTickimgsrc
this.$nextTick(() => {
this.cropper = new window.Cropper(
this.$el.querySelector('.avatar-cropper > img'),
{
dragMode: 'move',
initialAspectRatio: 1,
aspectRatio: 1,
checkCrossOrigin: false,
checkOrientation: false,
guides: false,
center: false,
rotatable: false,
cropBoxResizable: false,
toggleDragModeOnDblclick: false,
//200x200
ready: () => {
const size = 200
const container = this.$el.querySelector('.avatar-cropper')
const top = (500 - size) / 2
const left = (container.offsetWidth - size) / 2
this.cropper.setCropBoxData({width: size, height: size, top, left})
}
reader.readAsArrayBuffer(file)
}
)
})
},
chooseImage() {
this.$refs.input.click()
},
confirm() {
if (!this.img) return elError('请先上传图片')
if (this.loading) return
this.loading = true
this.$refs.cropper.getCropBlob(data => {
upload(new Blob([data]), this.name)
.then(({data}) => updateAvatar.request(data.data))
this.cropper
.getCroppedCanvas()
.toBlob(
data => {
upload(data, this.name)
.then(({key}) => updateAvatar.request(key))
.then(({data, msg}) => {
this.$store.commit('user/avatar', autoCompleteUrl(data))
this.$store.dispatch('user/refresh')
elSuccess(msg)
this.closeDialog()
})
.finally(() => this.cancel())
})
.finally(() => this.loading = false)
},
this.type
)
}
},
cancel() {
this.closeDialog()
beforeDestroy() {
this.clear()
}
}
}
</script>
@ -122,15 +153,32 @@ export default {
.avatar-cropper {
height: 500px;
width: 100%;
border: 1px solid #ebebeb;
.cropper-crop-box {
border-radius: 50%;
overflow: hidden;
&-bg {
height: 100%;
width: 100%;
cursor: pointer;
}
> img {
display: none;
height: 100%;
width: 100%;
}
> input[type=file] {
display: none;
}
.cropper-view-box {
border-radius: 50%;
box-sizing: border-box;
border: 1px solid rgba(51, 153, 255, .75);
outline: unset;
}
.cropper-face {
border-radius: 50%;
}
}
</style>

Loading…
Cancel
Save