Skip to content

Commit 33db8e9

Browse files
committed
feat: pick image from image gallery
1 parent acd5999 commit 33db8e9

File tree

8 files changed

+377
-3
lines changed

8 files changed

+377
-3
lines changed

front-end/h5/src/components/core/styles/index.scss

+5
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@
172172
justify-content: center;
173173
}
174174

175+
.flex-space-between {
176+
display: flex !important;
177+
justify-content: space-between;
178+
}
179+
175180
.cursor-pointer {
176181
cursor: pointer !important;
177182
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
export default {
2+
props: {
3+
item: {
4+
type: Object,
5+
default: () => ({})
6+
},
7+
height: {
8+
type: Number,
9+
default: 142
10+
}
11+
},
12+
render (h) {
13+
if (this.item.loading) {
14+
return <a-spin>
15+
<a-card hoverable>
16+
<div
17+
slot="cover"
18+
style={{
19+
height: `${this.height}px`
20+
}}>
21+
</div>
22+
</a-card>
23+
</a-spin>
24+
}
25+
return (
26+
<a-card
27+
hoverable
28+
>
29+
<div
30+
slot="cover"
31+
style={{
32+
backgroundImage: `url(${this.item.previewURL})`,
33+
backgroundSize: 'cover',
34+
height: `${this.height}px`
35+
}}>
36+
</div>
37+
</a-card>
38+
)
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
export default {
2+
props: {
3+
visible: {
4+
type: Boolean,
5+
default: false
6+
},
7+
handleClose: {
8+
type: Function,
9+
default: () => {}
10+
},
11+
uploadSuccess: {
12+
type: Function,
13+
default: () => {}
14+
},
15+
beforeUpload: {
16+
type: Function,
17+
default: (file) => file
18+
}
19+
},
20+
computed: {
21+
},
22+
data: () => ({
23+
loading: false
24+
}),
25+
methods: {
26+
handleBeforeUpload (file) {
27+
return this.beforeUpload(file)
28+
},
29+
handleChange (info) {
30+
this.loading = true
31+
const status = info.file.status
32+
if (status !== 'uploading') {
33+
console.log(info.file, info.fileList)
34+
}
35+
if (status === 'done') {
36+
this.loading = false
37+
this.uploadSuccess(info)
38+
this.$message.success(`${info.file.name} file uploaded successfully.`)
39+
} else if (status === 'error') {
40+
this.$message.error(`${info.file.name} file upload failed.`)
41+
}
42+
}
43+
},
44+
render (h) {
45+
return (
46+
<a-upload
47+
name="files"
48+
action="/upload"
49+
beforeUpload={this.handleBeforeUpload}
50+
onChange={this.handleChange}>
51+
<slot>
52+
<a-button>
53+
<a-icon type="upload" /> Click to Upload
54+
</a-button>
55+
</slot>
56+
</a-upload>
57+
)
58+
},
59+
mounted () {
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import './gallery.scss'
2+
import PersonalTab from './tabs/personal.js'
3+
import PixabayTab from './tabs/pixabay.js'
4+
5+
export default {
6+
components: {
7+
},
8+
props: {
9+
visible: {
10+
type: Boolean,
11+
default: false
12+
},
13+
value: {
14+
type: String,
15+
default: ''
16+
}
17+
},
18+
data: () => ({
19+
tabs: [
20+
{
21+
value: 'personal',
22+
label: '我的图库'
23+
},
24+
{
25+
value: 'pixabay',
26+
label: 'Pixabay图库'
27+
}
28+
],
29+
activeTab: 'personal',
30+
innerVisible: false,
31+
pixabayList: []
32+
}),
33+
computed: {
34+
},
35+
watch: {
36+
visible (value) {
37+
this.innerVisible = value
38+
}
39+
},
40+
methods: {
41+
handleClose () {
42+
this.innerVisible = false
43+
},
44+
changeTab ({ key }) {
45+
this.activeTab = key
46+
},
47+
handleSelectImage (item) {
48+
this.handleClose()
49+
this.$emit('change', item.previewURL)
50+
},
51+
renderContent () {
52+
switch (this.activeTab) {
53+
case 'personal':
54+
return <PersonalTab onChangeItem={item => {
55+
this.handleSelectImage(item)
56+
}}/>
57+
case 'pixabay':
58+
return <PixabayTab onChange={item => {
59+
this.handleSelectImage(item)
60+
}}/>
61+
}
62+
},
63+
renderDefaultActivator () {
64+
const activatorWithoutImg = (
65+
<div
66+
class="default-activator cursor-pointer "
67+
onClick={() => { this.innerVisible = true }}
68+
>
69+
<a-icon type="plus" />
70+
</div>
71+
)
72+
73+
const activatorWithImg = (
74+
<div
75+
class="default-activator cursor-pointer "
76+
onClick={() => { this.innerVisible = true }}
77+
>
78+
<img src={this.value} style={{ width: '100%' }} />
79+
<div class="flex-space-between" style="margin-top: 8px;">
80+
<a-button>更换图片</a-button>
81+
<a-button onClick={e => {
82+
e.stopPropagation()
83+
}}>裁剪图片</a-button>
84+
</div>
85+
</div>
86+
)
87+
return (this.value ? activatorWithImg : activatorWithoutImg)
88+
}
89+
},
90+
render (h) {
91+
return (
92+
<div>
93+
<slot>{this.renderDefaultActivator()}</slot>
94+
<a-modal
95+
closable
96+
title="图片库"
97+
width="65%"
98+
visible={this.innerVisible}
99+
onOk={this.handleClose}
100+
onCancel={this.handleClose}
101+
bodyStyle={{ margin: 0, padding: 0 }}
102+
>
103+
<a-layout style="height: 500px; position: relative;">
104+
<a-layout-sider width="200px" style="background-color: white;">
105+
<a-menu mode="inline" defaultSelectedKeys={['personal']} onClick={this.changeTab}>
106+
{
107+
this.tabs.map((tab, index) => (
108+
<a-menu-item key={tab.value} >
109+
<a-icon type="user" />
110+
<span>{tab.label}</span>
111+
</a-menu-item>
112+
))
113+
}
114+
</a-menu>
115+
</a-layout-sider>
116+
<a-layout-content>
117+
{this.renderContent()}
118+
</a-layout-content>
119+
</a-layout>
120+
</a-modal>
121+
</div>
122+
)
123+
}
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.default-activator {
2+
border: 1px dashed #eee;
3+
text-align: center;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import axios from 'axios'
2+
import ImageItem from '../components/image-item.js'
3+
import Uploader from '../components/uploader.js'
4+
5+
export default {
6+
data: () => ({
7+
items: [],
8+
cachedItems: [],
9+
loading: false
10+
}),
11+
methods: {
12+
uploadSuccess ({ file, fileList }) {
13+
const response = file.response.length && file.response[0]
14+
this.items = [{ name: response.name, previewURL: response.url }, ...this.cachedItems]
15+
},
16+
beforeUpload (file) {
17+
this.items.unshift({
18+
loading: true
19+
})
20+
return file
21+
}
22+
},
23+
render (h) {
24+
return (
25+
<div>
26+
<a-spin tip="Loading..." spinning={this.loading}>
27+
<a-card>
28+
<Uploader
29+
slot="extra"
30+
beforeUpload={file => this.beforeUpload(file)}
31+
uploadSuccess={info => this.uploadSuccess(info)}
32+
/>
33+
<a-list
34+
style="height: 400px; overflow: auto;"
35+
grid={{ gutter: 12, column: 3 }}
36+
dataSource={this.items}
37+
renderItem={(item, index) => (
38+
<a-list-item onClick={() => {
39+
debugger
40+
this.$emit('changeItem', item)
41+
}}>
42+
<ImageItem item={item} />
43+
</a-list-item>
44+
)}
45+
>
46+
</a-list>
47+
</a-card>
48+
</a-spin>
49+
</div>
50+
)
51+
},
52+
mounted () {
53+
// demo code
54+
axios
55+
.get('https://pixabay.com/api/?key=12120348-2ad26e4cc05d9bc068097ab3b&q=yellow+flowers&image_type=photo&pretty=true')
56+
.then(res => {
57+
this.items = res.data.hits
58+
this.cachedItems = res.data.hits.slice(0)
59+
})
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import axios from 'axios'
2+
import ImageItem from '../components/image-item.js'
3+
4+
export default {
5+
data: () => ({
6+
items: [],
7+
loading: false,
8+
options: {
9+
key: '12120348-2ad26e4cc05d9bc068097ab3b', // pixabay demo key from https://pixabay.com/zh/service/about/api/
10+
image_type: 'photo',
11+
pretty: true,
12+
q: 'yellow+flowers',
13+
orientation: 'all' // "all", "horizontal", "vertical"
14+
}
15+
}),
16+
computed: {
17+
isVertial () {
18+
return this.options.orientation === 'vertical'
19+
}
20+
},
21+
methods: {
22+
queryAPI () {
23+
axios
24+
.get('https://pixabay.com/api/', { params: this.options })
25+
.then(res => {
26+
this.items = res.data.hits
27+
})
28+
}
29+
},
30+
render (h) {
31+
return (
32+
<div>
33+
<a-spin tip="Loading..." spinning={this.loading}>
34+
<a-card >
35+
<div slot="extra" style={{ display: 'flex' }}>
36+
<a-dropdown>
37+
<a-menu slot="overlay" onClick={({ key }) => {
38+
this.options.orientation = key
39+
this.queryAPI()
40+
}}>
41+
<a-menu-item key="all"><a-icon type="user" />任意方位</a-menu-item>
42+
<a-menu-item key="horizontal"><a-icon type="user" />水平</a-menu-item>
43+
<a-menu-item key="vertical"><a-icon type="user" />竖直</a-menu-item>
44+
</a-menu>
45+
<a-button style="margin-left: 8px" type="link">
46+
图片方向 <a-icon type="down" />
47+
</a-button>
48+
</a-dropdown>
49+
<a-input-search
50+
placeholder="input search text"
51+
onSearch={value => {
52+
this.options.q = value
53+
this.queryAPI()
54+
}}
55+
/>
56+
</div>
57+
<a-list
58+
grid={{ gutter: 12, column: this.isVertial ? 4 : 3 }}
59+
dataSource={this.items}
60+
renderItem={(item, index) => (
61+
<a-list-item onClick={item => {
62+
this.$emit('changeItem', item)
63+
}}>
64+
<ImageItem item={item} height={this.isVertial ? 240 : 142 } />
65+
</a-list-item>
66+
)}
67+
>
68+
</a-list>
69+
</a-card>
70+
</a-spin>
71+
</div>
72+
)
73+
},
74+
mounted () {
75+
this.queryAPI()
76+
}
77+
}

0 commit comments

Comments
 (0)