Skip to content

Commit afdbeac

Browse files
新增图片裁剪组件Cropper
1 parent f1feef1 commit afdbeac

File tree

16 files changed

+266
-15
lines changed

16 files changed

+266
-15
lines changed

src/api/data.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ export const saveErrorLogger = info => {
2828
method: 'post'
2929
})
3030
}
31+
32+
export const uploadImg = formData => {
33+
return axios.request({
34+
url: 'image/upload',
35+
data: formData
36+
})
37+
}

src/assets/icons/iconfont.css

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11

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

1010
.iconfont {
@@ -19,6 +19,10 @@
1919

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

22+
.icon-chuizhifanzhuan:before { content: "\e661"; }
23+
24+
.icon-shuipingfanzhuan:before { content: "\e662"; }
25+
2226
.icon-qq:before { content: "\e609"; }
2327

2428
.icon-frown:before { content: "\e77e"; }

src/assets/icons/iconfont.eot

-4 Bytes
Binary file not shown.

src/assets/icons/iconfont.svg

Lines changed: 5 additions & 6 deletions
Loading

src/assets/icons/iconfont.ttf

-4 Bytes
Binary file not shown.

src/assets/icons/iconfont.woff

-64 Bytes
Binary file not shown.

src/components/cropper/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Cropper from './index.vue'
2+
export default Cropper

src/components/cropper/index.less

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.bg{
2+
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")
3+
}
4+
.cropper-wrapper{
5+
width: 600px;
6+
height: 340px;
7+
.img-box{
8+
height: 340px;
9+
width: 430px;
10+
border: 1px solid #ebebeb;
11+
display: inline-block;
12+
.bg;
13+
img{
14+
max-width: 100%;
15+
display: block;
16+
}
17+
}
18+
.right-con{
19+
display: inline-block;
20+
width: 170px;
21+
vertical-align: top;
22+
box-sizing: border-box;
23+
padding: 0 10px;
24+
.preview-box{
25+
height: 150px !important;
26+
width: 100% !important;
27+
overflow: hidden;
28+
border: 1px solid #ebebeb;
29+
.bg;
30+
}
31+
.button-box{
32+
padding: 10px 0 0;
33+
}
34+
}
35+
}

src/components/cropper/index.vue

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<template>
2+
<div class="cropper-wrapper">
3+
<div class="img-box">
4+
<img class="cropper-image" :id="imgId" alt="">
5+
</div>
6+
<div class="right-con">
7+
<div v-if="preview" class="preview-box" :id="previewId"></div>
8+
<div class="button-box">
9+
<slot>
10+
<Upload action="image/upload" :before-upload="beforeUpload">
11+
<Button style="width: 150px;" type="primary">上传图片</Button>
12+
</Upload>
13+
</slot>
14+
<div v-show="insideSrc">
15+
<Button type="primary" @click="rotate">
16+
<Icon type="md-refresh" :size="18"/>
17+
</Button>
18+
<Button type="primary" @click="shrink">
19+
<Icon type="md-remove" :size="18"/>
20+
</Button>
21+
<Button type="primary" @click="magnify">
22+
<Icon type="md-add" :size="18"/>
23+
</Button>
24+
<Button type="primary" @click="scale('X')">
25+
<Icon custom="iconfont icon-shuipingfanzhuan" :size="18"/>
26+
</Button>
27+
<Button type="primary" @click="scale('Y')">
28+
<Icon custom="iconfont icon-chuizhifanzhuan" :size="18"/>
29+
</Button>
30+
<Button type="primary" @click="move(0, -moveStep)">
31+
<Icon type="md-arrow-round-up" :size="18"/>
32+
</Button>
33+
<Button type="primary" @click="move(-moveStep, 0)">
34+
<Icon type="md-arrow-round-back" :size="18"/>
35+
</Button>
36+
<Button type="primary" @click="move(0, moveStep)">
37+
<Icon type="md-arrow-round-down" :size="18"/>
38+
</Button>
39+
<Button type="primary" @click="move(moveStep, 0)">
40+
<Icon type="md-arrow-round-forward" :size="18"/>
41+
</Button>
42+
<Button style="width: 150px;margin-top: 10px;" type="primary" @click="crop">{{ cropButtonText }}</Button>
43+
</div>
44+
</div>
45+
</div>
46+
</div>
47+
</template>
48+
49+
<script>
50+
import Cropper from 'cropperjs'
51+
import './index.less'
52+
import 'cropperjs/dist/cropper.min.css'
53+
export default {
54+
name: 'Cropper',
55+
props: {
56+
src: {
57+
type: String,
58+
default: ''
59+
},
60+
preview: {
61+
type: Boolean,
62+
default: true
63+
},
64+
moveStep: {
65+
type: Number,
66+
default: 4
67+
},
68+
cropButtonText: {
69+
type: String,
70+
default: '裁剪'
71+
}
72+
},
73+
data () {
74+
return {
75+
cropper: null,
76+
insideSrc: ''
77+
}
78+
},
79+
computed: {
80+
imgId () {
81+
return `cropper${this._uid}`
82+
},
83+
previewId () {
84+
return `cropper_preview${this._uid}`
85+
}
86+
},
87+
watch: {
88+
src (src) {
89+
this.replace(src)
90+
},
91+
insideSrc (src) {
92+
this.replace(src)
93+
}
94+
},
95+
methods: {
96+
beforeUpload (file) {
97+
const reader = new FileReader()
98+
reader.readAsDataURL(file)
99+
reader.onload = (event) => {
100+
this.insideSrc = event.srcElement.result
101+
}
102+
return false
103+
},
104+
replace (src) {
105+
this.cropper.replace(src)
106+
this.insideSrc = src
107+
},
108+
rotate () {
109+
this.cropper.rotate(90)
110+
},
111+
shrink () {
112+
this.cropper.zoom(-0.1)
113+
},
114+
magnify () {
115+
this.cropper.zoom(0.1)
116+
},
117+
scale (d) {
118+
this.cropper[`scale${d}`](-this.cropper.getData()[`scale${d}`])
119+
},
120+
move (...argu) {
121+
this.cropper.move(...argu)
122+
},
123+
crop () {
124+
this.cropper.getCroppedCanvas().toBlob(blob => {
125+
this.$emit('on-crop', blob)
126+
})
127+
}
128+
},
129+
mounted () {
130+
this.$nextTick(() => {
131+
let dom = document.getElementById(this.imgId)
132+
this.cropper = new Cropper(dom, {
133+
preview: `#${this.previewId}`,
134+
checkCrossOrigin: true
135+
})
136+
})
137+
}
138+
}
139+
</script>

src/locale/lang/en-US.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ export default {
3434
error_store_page: 'Error Collection',
3535
error_logger_page: 'Error Logger',
3636
query: 'Query',
37-
params: 'Params'
37+
params: 'Params',
38+
cropper_page: 'Cropper'
3839
}

src/locale/lang/zh-CN.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ export default {
3434
error_store_page: '错误收集',
3535
error_logger_page: '错误日志',
3636
query: '带参路由',
37-
params: '动态路由'
37+
params: '动态路由',
38+
cropper_page: '图片裁剪'
3839
}

src/locale/lang/zh-TW.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ export default {
3434
error_store_page: '錯誤收集',
3535
error_logger_page: '錯誤日誌',
3636
query: '帶參路由',
37-
params: '動態路由'
37+
params: '動態路由',
38+
cropper_page: '圖片裁剪'
3839
}

src/mock/data.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@ export const getDragList = req => {
2424
})
2525
return dragList
2626
}
27+
28+
export const uploadImage = req => {
29+
return Promise.resolve()
30+
}

src/mock/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Mock from 'mockjs'
22
import { login, logout, getUserInfo } from './login'
3-
import { getTableData, getDragList } from './data'
3+
import { getTableData, getDragList, uploadImage } from './data'
44

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

1314
export default Mock

0 commit comments

Comments
 (0)