Skip to content

Commit 5913cf9

Browse files
chswordtangjinzhou
andauthored
feat: add image (#3235)
* feat: 🆕 image组件 - 添加样式 * feat: 🆕 增加 AImage 组件 * feat: 🆕 参考 ant-design 增加 相关 Image 组件的less定义 * feat: 🆕 Image placeholder 的修改 * fix: 🐞 去除 onPreviewClose 相关 * test: 🧪 image width/height 以及相关测试 * fix: 🐞 fix lint no-setup-props-destructure * test: 🧪 image test snap file * refactor: 💡 去掉多加了的文件,重构文件以使逻辑清晰 * feat: 🆕 rc-image 相关内容 列入 vc-image 文件夹中 * feat: 🆕 antd 4.9.1 增加 image-preview-group * feat: 🆕 add ImagePropsType * feat: udpate image components * feat: update image * feat: update image Co-authored-by: tanjinzhou <[email protected]>
1 parent c6b189b commit 5913cf9

23 files changed

+1521
-2
lines changed

antdv-demo

components/image/PreviewGroup.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import PreviewGroup from '../vc-image/src/PreviewGroup';
2+
import { defineComponent, inject } from 'vue';
3+
import { defaultConfigProvider } from '../config-provider';
4+
import PropTypes from '../_util/vue-types';
5+
6+
const InternalPreviewGroup = defineComponent({
7+
name: 'AImagePreviewGroup',
8+
inheritAttrs: false,
9+
props: { previewPrefixCls: PropTypes.string },
10+
setup(props, { attrs, slots }) {
11+
const configProvider = inject('configProvider', defaultConfigProvider);
12+
return () => {
13+
const { getPrefixCls } = configProvider;
14+
const prefixCls = getPrefixCls('image-preview', props.previewPrefixCls);
15+
return (
16+
<PreviewGroup
17+
previewPrefixCls={prefixCls}
18+
{...{ ...attrs, ...props }}
19+
v-slots={slots}
20+
></PreviewGroup>
21+
);
22+
};
23+
},
24+
});
25+
export default InternalPreviewGroup;

components/image/__tests__/__snapshots__/demo.test.js.snap

Whitespace-only changes.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import demoTest from '../../../tests/shared/demoTest';
2+
3+
demoTest('image');
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Image from '..';
2+
import mountTest from '../../../tests/shared/mountTest';
3+
import { mount } from '@vue/test-utils';
4+
describe('Image', () => {
5+
mountTest(Image);
6+
it('image size', () => {
7+
const wrapper = mount({
8+
render() {
9+
return (
10+
<Image
11+
width="200px"
12+
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
13+
/>
14+
);
15+
},
16+
});
17+
expect(wrapper.find('.ant-image').element.style.width).toBe('200px');
18+
});
19+
it('image size number', () => {
20+
const wrapper = mount({
21+
render() {
22+
return (
23+
<Image
24+
width={200}
25+
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
26+
/>
27+
);
28+
},
29+
});
30+
expect(wrapper.find('.ant-image').element.style.width).toBe('200px');
31+
});
32+
});

components/image/index.tsx

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { App, defineComponent, inject, Plugin } from 'vue';
2+
import { defaultConfigProvider } from '../config-provider';
3+
import ImageInternal from '../vc-image';
4+
import { ImageProps, ImagePropsType } from '../vc-image/src/Image';
5+
6+
import PreviewGroup from './PreviewGroup';
7+
const Image = defineComponent({
8+
name: 'AImage',
9+
inheritAttrs: false,
10+
props: ImageProps,
11+
setup(props, ctx) {
12+
const { slots, attrs } = ctx;
13+
const configProvider = inject('configProvider', defaultConfigProvider);
14+
return () => {
15+
const { getPrefixCls } = configProvider;
16+
const prefixCls = getPrefixCls('image', props.prefixCls);
17+
return <ImageInternal {...{ ...attrs, ...props, prefixCls }} v-slots={slots}></ImageInternal>;
18+
};
19+
},
20+
});
21+
22+
export { ImageProps, ImagePropsType };
23+
24+
Image.PreviewGroup = PreviewGroup;
25+
26+
Image.install = function(app: App) {
27+
app.component(Image.name, Image);
28+
app.component(Image.PreviewGroup.name, Image.PreviewGroup);
29+
return app;
30+
};
31+
32+
export default Image as typeof Image &
33+
Plugin & {
34+
readonly PreviewGroup: typeof PreviewGroup;
35+
};

components/image/style/index.less

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
@import '../../style/themes/index';
2+
@import '../../style/mixins/index';
3+
4+
@image-prefix-cls: ~'@{ant-prefix}-image';
5+
@image-preview-prefix-cls: ~'@{image-prefix-cls}-preview';
6+
7+
.@{image-prefix-cls} {
8+
position: relative;
9+
display: inline-block;
10+
&-img {
11+
width: 100%;
12+
height: auto;
13+
&-placeholder {
14+
background-color: @image-bg;
15+
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuNSAyLjVoLTEzQS41LjUgMCAwIDAgMSAzdjEwYS41LjUgMCAwIDAgLjUuNWgxM2EuNS41IDAgMCAwIC41LS41VjNhLjUuNSAwIDAgMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwIDEgMCAyIDEgMSAwIDAgMSAwLTJ6bTguMDMgNi44M2EuMTI3LjEyNyAwIDAgMS0uMDgxLjAzSDIuNzY5YS4xMjUuMTI1IDAgMCAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAgMSAuMTc3LS4wMTZsLjAxNi4wMTZMNy4wOCAxMC4wOWwyLjQ3LTIuOTNhLjEyNi4xMjYgMCAwIDEgLjE3Ny0uMDE2bC4wMTUuMDE2IDMuNTg4IDQuMjQ0YS4xMjcuMTI3IDAgMCAxLS4wMi4xNzV6IiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=);
16+
background-repeat: no-repeat;
17+
background-position: center center;
18+
background-size: 30%;
19+
}
20+
}
21+
22+
&-placeholder {
23+
.box;
24+
}
25+
26+
&-preview {
27+
.modal-mask;
28+
29+
height: 100%;
30+
text-align: center;
31+
32+
&-body {
33+
.box;
34+
overflow: hidden;
35+
}
36+
37+
&-img {
38+
max-width: 100%;
39+
max-height: 100%;
40+
vertical-align: middle;
41+
transform: scale3d(1, 1, 1);
42+
cursor: grab;
43+
transition: transform 0.3s @ease-out 0s;
44+
user-select: none;
45+
pointer-events: auto;
46+
&-wrapper {
47+
.box;
48+
transition: transform 0.3s @ease-out 0s;
49+
&::before {
50+
display: inline-block;
51+
width: 1px;
52+
height: 50%;
53+
margin-right: -1px;
54+
content: '';
55+
}
56+
}
57+
}
58+
59+
&-moving {
60+
.@{image-prefix-cls}-preview-img {
61+
cursor: grabbing;
62+
&-wrapper {
63+
transition-duration: 0s;
64+
}
65+
}
66+
}
67+
68+
&-wrap {
69+
z-index: @zindex-image;
70+
}
71+
72+
&-operations {
73+
.reset-component;
74+
position: absolute;
75+
top: 0;
76+
right: 0;
77+
z-index: 1;
78+
display: flex;
79+
flex-direction: row-reverse;
80+
align-items: center;
81+
width: 100%;
82+
color: @image-preview-operation-color;
83+
list-style: none;
84+
background: fade(@modal-mask-bg, 10%);
85+
pointer-events: auto;
86+
87+
&-operation {
88+
margin-left: @control-padding-horizontal;
89+
padding: @control-padding-horizontal;
90+
cursor: pointer;
91+
&-disabled {
92+
color: @image-preview-operation-disabled-color;
93+
pointer-events: none;
94+
}
95+
&:last-of-type {
96+
margin-left: 0;
97+
}
98+
}
99+
&-icon {
100+
font-size: @image-preview-operation-size;
101+
}
102+
}
103+
104+
&-switch-left,
105+
&-switch-right {
106+
position: absolute;
107+
top: 50%;
108+
right: 10px;
109+
z-index: 1;
110+
display: flex;
111+
align-items: center;
112+
justify-content: center;
113+
width: 44px;
114+
height: 44px;
115+
margin-top: -22px;
116+
color: @image-preview-operation-color;
117+
background: fade(@modal-mask-bg, 10%);
118+
border-radius: 50%;
119+
cursor: pointer;
120+
pointer-events: auto;
121+
&-disabled {
122+
color: @image-preview-operation-disabled-color;
123+
cursor: not-allowed;
124+
> .anticon {
125+
cursor: not-allowed;
126+
}
127+
}
128+
> .anticon {
129+
font-size: 18px;
130+
}
131+
}
132+
133+
&-switch-left {
134+
left: 10px;
135+
}
136+
137+
&-switch-right {
138+
right: 10px;
139+
}
140+
}
141+
}

components/image/style/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import '../../style/index.less';
2+
import './index.less';

components/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ import { default as Drawer } from './drawer';
133133
import { default as Skeleton } from './skeleton';
134134

135135
import { default as Comment } from './comment';
136-
136+
import { default as Image } from './image';
137137
// import { default as ColorPicker } from './color-picker';
138138

139139
import { default as ConfigProvider } from './config-provider';
@@ -209,6 +209,7 @@ const components = [
209209
Descriptions,
210210
PageHeader,
211211
Space,
212+
Image,
212213
];
213214

214215
const install = function(app: App) {
@@ -296,6 +297,7 @@ export {
296297
Descriptions,
297298
PageHeader,
298299
Space,
300+
Image,
299301
};
300302

301303
export default {

components/style.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,5 @@ import './descriptions/style';
6060
import './page-header/style';
6161
import './form/style';
6262
import './space/style';
63+
import './image/style';
6364
// import './color-picker/style';

components/style/mixins/box.less

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.box(@position: absolute) {
2+
position: @position;
3+
top: 0;
4+
right: 0;
5+
bottom: 0;
6+
left: 0;
7+
}

components/style/mixins/index.less

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@
88
@import 'reset';
99
@import 'operation-unit';
1010
@import 'typography';
11+
@import 'box';
12+
@import 'modal-mask';
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@import 'box';
2+
3+
.modal-mask() {
4+
pointer-events: none;
5+
6+
&.zoom-enter,
7+
&.zoom-appear {
8+
transform: none; // reset scale avoid mousePosition bug
9+
opacity: 0;
10+
animation-duration: @animation-duration-slow;
11+
user-select: none; // https://github.com/ant-design/ant-design/issues/11777
12+
}
13+
14+
&-mask {
15+
.box(fixed);
16+
z-index: @zindex-modal-mask;
17+
height: 100%;
18+
background-color: @modal-mask-bg;
19+
20+
&-hidden {
21+
display: none;
22+
}
23+
}
24+
25+
&-wrap {
26+
.box(fixed);
27+
overflow: auto;
28+
outline: 0;
29+
-webkit-overflow-scrolling: touch;
30+
}
31+
}

components/style/themes/default.less

+11
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@
288288
@zindex-dropdown: 1050;
289289
@zindex-picker: 1050;
290290
@zindex-tooltip: 1060;
291+
@zindex-image: 1080;
291292

292293
// Animation
293294
@animation-duration-slow: 0.3s; // Modal
@@ -720,3 +721,13 @@
720721
@typography-title-font-weight: 600;
721722
@typography-title-margin-top: 1.2em;
722723
@typography-title-margin-bottom: 0.5em;
724+
725+
// Image
726+
// ---
727+
@image-size-base: 48px;
728+
@image-font-size-base: 24px;
729+
@image-bg: #f5f5f5;
730+
@image-color: #fff;
731+
@image-preview-operation-size: 18px;
732+
@image-preview-operation-color: @text-color-dark;
733+
@image-preview-operation-disabled-color: fade(@image-preview-operation-color, 45%);

0 commit comments

Comments
 (0)