Skip to content

Commit

Permalink
新增图片裁剪组件Cropper
Browse files Browse the repository at this point in the history
  • Loading branch information
zhigang.li@tendcloud.com committed Nov 7, 2018
1 parent f1feef1 commit afdbeac
Show file tree
Hide file tree
Showing 16 changed files with 266 additions and 15 deletions.
7 changes: 7 additions & 0 deletions src/api/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@ export const saveErrorLogger = info => {
method: 'post'
})
}

export const uploadImg = formData => {
return axios.request({
url: 'image/upload',
data: formData
})
}
14 changes: 9 additions & 5 deletions src/assets/icons/iconfont.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1530874958372'); /* IE9*/
src: url('iconfont.eot?t=1530874958372#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
url('iconfont.ttf?t=1530874958372') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('iconfont.svg?t=1530874958372#iconfont') format('svg'); /* iOS 4.1- */
src: url('iconfont.eot?t=1541579316141'); /* IE9*/
src: url('iconfont.eot?t=1541579316141#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
url('iconfont.ttf?t=1541579316141') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('iconfont.svg?t=1541579316141#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
Expand All @@ -19,6 +19,10 @@

.icon-resize-vertical:before { content: "\e7c3"; }

.icon-chuizhifanzhuan:before { content: "\e661"; }

.icon-shuipingfanzhuan:before { content: "\e662"; }

.icon-qq:before { content: "\e609"; }

.icon-frown:before { content: "\e77e"; }
Expand Down
Binary file modified src/assets/icons/iconfont.eot
Binary file not shown.
11 changes: 5 additions & 6 deletions src/assets/icons/iconfont.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/assets/icons/iconfont.ttf
Binary file not shown.
Binary file modified src/assets/icons/iconfont.woff
Binary file not shown.
2 changes: 2 additions & 0 deletions src/components/cropper/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Cropper from './index.vue'
export default Cropper
35 changes: 35 additions & 0 deletions src/components/cropper/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.bg{
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")
}
.cropper-wrapper{
width: 600px;
height: 340px;
.img-box{
height: 340px;
width: 430px;
border: 1px solid #ebebeb;
display: inline-block;
.bg;
img{
max-width: 100%;
display: block;
}
}
.right-con{
display: inline-block;
width: 170px;
vertical-align: top;
box-sizing: border-box;
padding: 0 10px;
.preview-box{
height: 150px !important;
width: 100% !important;
overflow: hidden;
border: 1px solid #ebebeb;
.bg;
}
.button-box{
padding: 10px 0 0;
}
}
}
139 changes: 139 additions & 0 deletions src/components/cropper/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<template>
<div class="cropper-wrapper">
<div class="img-box">
<img class="cropper-image" :id="imgId" alt="">
</div>
<div class="right-con">
<div v-if="preview" class="preview-box" :id="previewId"></div>
<div class="button-box">
<slot>
<Upload action="image/upload" :before-upload="beforeUpload">
<Button style="width: 150px;" type="primary">上传图片</Button>
</Upload>
</slot>
<div v-show="insideSrc">
<Button type="primary" @click="rotate">
<Icon type="md-refresh" :size="18"/>
</Button>
<Button type="primary" @click="shrink">
<Icon type="md-remove" :size="18"/>
</Button>
<Button type="primary" @click="magnify">
<Icon type="md-add" :size="18"/>
</Button>
<Button type="primary" @click="scale('X')">
<Icon custom="iconfont icon-shuipingfanzhuan" :size="18"/>
</Button>
<Button type="primary" @click="scale('Y')">
<Icon custom="iconfont icon-chuizhifanzhuan" :size="18"/>
</Button>
<Button type="primary" @click="move(0, -moveStep)">
<Icon type="md-arrow-round-up" :size="18"/>
</Button>
<Button type="primary" @click="move(-moveStep, 0)">
<Icon type="md-arrow-round-back" :size="18"/>
</Button>
<Button type="primary" @click="move(0, moveStep)">
<Icon type="md-arrow-round-down" :size="18"/>
</Button>
<Button type="primary" @click="move(moveStep, 0)">
<Icon type="md-arrow-round-forward" :size="18"/>
</Button>
<Button style="width: 150px;margin-top: 10px;" type="primary" @click="crop">{{ cropButtonText }}</Button>
</div>
</div>
</div>
</div>
</template>

<script>
import Cropper from 'cropperjs'
import './index.less'
import 'cropperjs/dist/cropper.min.css'
export default {
name: 'Cropper',
props: {
src: {
type: String,
default: ''
},
preview: {
type: Boolean,
default: true
},
moveStep: {
type: Number,
default: 4
},
cropButtonText: {
type: String,
default: '裁剪'
}
},
data () {
return {
cropper: null,
insideSrc: ''
}
},
computed: {
imgId () {
return `cropper${this._uid}`
},
previewId () {
return `cropper_preview${this._uid}`
}
},
watch: {
src (src) {
this.replace(src)
},
insideSrc (src) {
this.replace(src)
}
},
methods: {
beforeUpload (file) {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (event) => {
this.insideSrc = event.srcElement.result
}
return false
},
replace (src) {
this.cropper.replace(src)
this.insideSrc = src
},
rotate () {
this.cropper.rotate(90)
},
shrink () {
this.cropper.zoom(-0.1)
},
magnify () {
this.cropper.zoom(0.1)
},
scale (d) {
this.cropper[`scale${d}`](-this.cropper.getData()[`scale${d}`])
},
move (...argu) {
this.cropper.move(...argu)
},
crop () {
this.cropper.getCroppedCanvas().toBlob(blob => {
this.$emit('on-crop', blob)
})
}
},
mounted () {
this.$nextTick(() => {
let dom = document.getElementById(this.imgId)
this.cropper = new Cropper(dom, {
preview: `#${this.previewId}`,
checkCrossOrigin: true
})
})
}
}
</script>
3 changes: 2 additions & 1 deletion src/locale/lang/en-US.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ export default {
error_store_page: 'Error Collection',
error_logger_page: 'Error Logger',
query: 'Query',
params: 'Params'
params: 'Params',
cropper_page: 'Cropper'
}
3 changes: 2 additions & 1 deletion src/locale/lang/zh-CN.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ export default {
error_store_page: '错误收集',
error_logger_page: '错误日志',
query: '带参路由',
params: '动态路由'
params: '动态路由',
cropper_page: '图片裁剪'
}
3 changes: 2 additions & 1 deletion src/locale/lang/zh-TW.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ export default {
error_store_page: '錯誤收集',
error_logger_page: '錯誤日誌',
query: '帶參路由',
params: '動態路由'
params: '動態路由',
cropper_page: '圖片裁剪'
}
4 changes: 4 additions & 0 deletions src/mock/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ export const getDragList = req => {
})
return dragList
}

export const uploadImage = req => {
return Promise.resolve()
}
3 changes: 2 additions & 1 deletion src/mock/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Mock from 'mockjs'
import { login, logout, getUserInfo } from './login'
import { getTableData, getDragList } from './data'
import { getTableData, getDragList, uploadImage } from './data'

// 登录相关和获取用户信息
Mock.mock(/\/login/, login)
Expand All @@ -9,5 +9,6 @@ Mock.mock(/\/logout/, logout)
Mock.mock(/\/get_table_data/, getTableData)
Mock.mock(/\/get_drag_list/, getDragList)
Mock.mock(/\/save_error_logger/, 'success')
Mock.mock(/\/image\/upload/, uploadImage)

export default Mock
Loading

0 comments on commit afdbeac

Please sign in to comment.