Skip to content

Commit fc5181d

Browse files
authored
docs(QRCode): Synchronize QR code demonstration and add SVG (#6660)
* fix: Synchronize QR code demonstration and add SVG * fix: responsive loss and invalid border style * docs: synchronize antd5.6.3 QRCode color in dark mode
1 parent 994707b commit fc5181d

15 files changed

+195
-21
lines changed

components/qrcode/QRCodeCanvas.tsx renamed to components/qrcode/QRCode.tsx

+82
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,85 @@ export const QRCodeCanvas = defineComponent({
265265
};
266266
},
267267
});
268+
269+
export const QRCodeSVG = defineComponent({
270+
name: 'QRCodeSVG',
271+
inheritAttrs: false,
272+
props: {
273+
...qrProps(),
274+
color: String,
275+
level: String,
276+
bgColor: String,
277+
fgColor: String,
278+
marginSize: Number,
279+
title: String,
280+
},
281+
setup(props) {
282+
let cells = null;
283+
let margin = null;
284+
let numCells = null;
285+
let calculatedImageSettings = null;
286+
287+
let fgPath = null;
288+
let image = null;
289+
290+
watchEffect(() => {
291+
const {
292+
value,
293+
size = DEFAULT_SIZE,
294+
level = DEFAULT_LEVEL,
295+
includeMargin = DEFAULT_INCLUDEMARGIN,
296+
marginSize,
297+
imageSettings,
298+
} = props;
299+
300+
cells = qrcodegen.QrCode.encodeText(value, ERROR_LEVEL_MAP[level]).getModules();
301+
302+
margin = getMarginSize(includeMargin, marginSize);
303+
numCells = cells.length + margin * 2;
304+
calculatedImageSettings = getImageSettings(cells, size, margin, imageSettings);
305+
306+
if (imageSettings != null && calculatedImageSettings != null) {
307+
if (calculatedImageSettings.excavation != null) {
308+
cells = excavateModules(cells, calculatedImageSettings.excavation);
309+
}
310+
311+
image = (
312+
<image
313+
xlinkHref={imageSettings.src}
314+
height={calculatedImageSettings.h}
315+
width={calculatedImageSettings.w}
316+
x={calculatedImageSettings.x + margin}
317+
y={calculatedImageSettings.y + margin}
318+
preserveAspectRatio="none"
319+
/>
320+
);
321+
}
322+
323+
// Drawing strategy: instead of a rect per module, we're going to create a
324+
// single path for the dark modules and layer that on top of a light rect,
325+
// for a total of 2 DOM nodes. We pay a bit more in string concat but that's
326+
// way faster than DOM ops.
327+
// For level 1, 441 nodes -> 2
328+
// For level 40, 31329 -> 2
329+
fgPath = generatePath(cells, margin);
330+
});
331+
332+
return () => {
333+
const bgColor = props.bgColor && DEFAULT_BGCOLOR;
334+
const fgColor = props.fgColor && DEFAULT_FGCOLOR;
335+
return (
336+
<svg height={props.size} width={props.size} viewBox={`0 0 ${numCells} ${numCells}`}>
337+
{!!props.title && <title>{props.title}</title>}
338+
<path
339+
fill={bgColor}
340+
d={`M0,0 h${numCells}v${numCells}H0z`}
341+
shape-rendering="crispEdges"
342+
/>
343+
<path fill={fgColor} d={fgPath} shape-rendering="crispEdges" />
344+
{image}
345+
</svg>
346+
);
347+
};
348+
},
349+
});

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

+23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,29 @@ exports[`renders ./components/qrcode/demo/customSize.vue correctly 1`] = `
3939
</div>
4040
`;
4141
42+
exports[`renders ./components/qrcode/demo/customType.vue correctly 1`] = `
43+
<div class="ant-space ant-space-horizontal ant-space-align-center">
44+
<div class="ant-space-item" style="margin-right: 8px;">
45+
<div style="width: 160px; height: 160px;" class="ant-qrcode">
46+
<!----><canvas style="height: 134px; width: 134px;"></canvas>
47+
<!---->
48+
</div>
49+
</div>
50+
<!---->
51+
<div class="ant-space-item">
52+
<div style="width: 160px; height: 160px;" class="ant-qrcode">
53+
<!----><svg height="134" width="134" viewBox="0 0 25 25">
54+
<title></title>
55+
<path fill="transparent" d="M0,0 h25v25H0z" shape-rendering="crispEdges"></path>
56+
<path fill="#000" d="M0 0h7v1H0zM10 0h1v1H10zM13 0h2v1H13zM18,0 h7v1H18zM0 1h1v1H0zM6 1h1v1H6zM8 1h1v1H8zM11 1h1v1H11zM14 1h1v1H14zM18 1h1v1H18zM24,1 h1v1H24zM0 2h1v1H0zM2 2h3v1H2zM6 2h1v1H6zM9 2h2v1H9zM12 2h3v1H12zM18 2h1v1H18zM20 2h3v1H20zM24,2 h1v1H24zM0 3h1v1H0zM2 3h3v1H2zM6 3h1v1H6zM8 3h4v1H8zM13 3h1v1H13zM15 3h2v1H15zM18 3h1v1H18zM20 3h3v1H20zM24,3 h1v1H24zM0 4h1v1H0zM2 4h3v1H2zM6 4h1v1H6zM8 4h2v1H8zM11 4h4v1H11zM18 4h1v1H18zM20 4h3v1H20zM24,4 h1v1H24zM0 5h1v1H0zM6 5h1v1H6zM13 5h2v1H13zM16 5h1v1H16zM18 5h1v1H18zM24,5 h1v1H24zM0 6h7v1H0zM8 6h1v1H8zM10 6h1v1H10zM12 6h1v1H12zM14 6h1v1H14zM16 6h1v1H16zM18,6 h7v1H18zM8 7h1v1H8zM13 7h1v1H13zM15 7h2v1H15zM1 8h1v1H1zM3 8h4v1H3zM8 8h1v1H8zM10 8h1v1H10zM14 8h2v1H14zM17 8h2v1H17zM20 8h2v1H20zM23 8h1v1H23zM0 9h1v1H0zM3 9h1v1H3zM7 9h3v1H7zM11 9h1v1H11zM13 9h3v1H13zM17 9h1v1H17zM19 9h5v1H19zM0 10h1v1H0zM2 10h1v1H2zM5 10h2v1H5zM8 10h1v1H8zM11 10h1v1H11zM15 10h1v1H15zM18 10h2v1H18zM21 10h1v1H21zM24,10 h1v1H24zM1 11h1v1H1zM3 11h3v1H3zM7 11h2v1H7zM11 11h1v1H11zM14 11h1v1H14zM19 11h1v1H19zM21,11 h4v1H21zM1 12h4v1H1zM6 12h3v1H6zM11 12h8v1H11zM24,12 h1v1H24zM0 13h1v1H0zM3 13h1v1H3zM5 13h1v1H5zM7 13h1v1H7zM9 13h8v1H9zM20 13h1v1H20zM23 13h1v1H23zM0 14h2v1H0zM3 14h1v1H3zM5 14h2v1H5zM8 14h1v1H8zM13 14h5v1H13zM20,14 h5v1H20zM0 15h1v1H0zM2 15h3v1H2zM8 15h3v1H8zM12 15h3v1H12zM19 15h2v1H19zM22 15h1v1H22zM24,15 h1v1H24zM0 16h1v1H0zM5 16h2v1H5zM8 16h2v1H8zM11 16h1v1H11zM15 16h6v1H15zM22 16h2v1H22zM8 17h2v1H8zM12 17h5v1H12zM20 17h1v1H20zM23 17h1v1H23zM0 18h7v1H0zM10 18h1v1H10zM12 18h2v1H12zM16 18h1v1H16zM18 18h1v1H18zM20 18h2v1H20zM24,18 h1v1H24zM0 19h1v1H0zM6 19h1v1H6zM8 19h1v1H8zM11 19h1v1H11zM14 19h3v1H14zM20 19h1v1H20zM24,19 h1v1H24zM0 20h1v1H0zM2 20h3v1H2zM6 20h1v1H6zM8 20h2v1H8zM13 20h1v1H13zM15 20h7v1H15zM23,20 h2v1H23zM0 21h1v1H0zM2 21h3v1H2zM6 21h1v1H6zM8 21h2v1H8zM12 21h1v1H12zM14 21h1v1H14zM17 21h3v1H17zM21 21h1v1H21zM23,21 h2v1H23zM0 22h1v1H0zM2 22h3v1H2zM6 22h1v1H6zM9 22h2v1H9zM12 22h2v1H12zM16 22h2v1H16zM19 22h2v1H19zM22,22 h3v1H22zM0 23h1v1H0zM6 23h1v1H6zM8 23h3v1H8zM12 23h1v1H12zM14 23h1v1H14zM17 23h4v1H17zM22,23 h3v1H22zM0 24h7v1H0zM11 24h3v1H11zM16 24h1v1H16zM18 24h1v1H18zM21 24h1v1H21zM24,24 h1v1H24z" shape-rendering="crispEdges"></path>
57+
<!---->
58+
</svg>
59+
</div>
60+
</div>
61+
<!---->
62+
</div>
63+
`;
64+
4265
exports[`renders ./components/qrcode/demo/download.vue correctly 1`] = `
4366
<div style="width: 160px; height: 160px;" class="ant-qrcode">
4467
<!----><canvas style="height: 134px; width: 134px;"></canvas>

components/qrcode/demo/base.vue

+10-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,14 @@ Basic Usage.
1515
</docs>
1616

1717
<template>
18-
<a-qrcode value="https://www.antdv.com/" />
18+
<a-space direction="vertical" align="center">
19+
<a-qrcode :value="text" />
20+
<a-input v-model:value="text" placeholder="-" :maxlength="60" />
21+
</a-space>
1922
</template>
23+
24+
<script lang="ts" setup>
25+
import { ref } from 'vue';
26+
27+
const text = ref('https://www.antdv.com/');
28+
</script>

components/qrcode/demo/customColor.vue

+13-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,18 @@ Custom Color.
1616

1717
<template>
1818
<a-space>
19-
<div><a-qrcode value="http://www.antv.com" color="#73d13d" /></div>
20-
<div><a-qrcode value="http://www.antv.com" color="#1677ff" /></div>
19+
<a-qrcode value="http://www.antdv.com" :color="token.colorSuccessText" />
20+
<a-qrcode
21+
value="http://www.antdv.com"
22+
:color="token.colorInfoText"
23+
:bg-color="token.colorBgLayout"
24+
/>
2125
</a-space>
2226
</template>
27+
28+
<script lang="ts" setup>
29+
import { theme } from 'ant-design-vue';
30+
31+
const { useToken } = theme;
32+
const { token } = useToken();
33+
</script>

components/qrcode/demo/customSize.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Custom Size.
3131
:size="size"
3232
:icon-size="size / 4"
3333
error-level="H"
34-
value="https://www.antv.com"
34+
value="https://www.antdv.com"
3535
icon="https://www.antdv.com/assets/logo.1ef800a8.svg"
3636
/>
3737
</template>

components/qrcode/demo/customType.vue

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<docs>
2+
---
3+
order: 4
4+
title:
5+
zh-CN: 自定义渲染类型
6+
en-US: Custom Render Type
7+
---
8+
9+
## zh-CN
10+
11+
通过设置 `type` 自定义渲染结果,提供 `canvas` 和 `svg` 两个选项。
12+
13+
## en-US
14+
Customize the rendering results by `type`, provide options `canvas` and `svg`.
15+
</docs>
16+
17+
<template>
18+
<a-space>
19+
<a-qrcode value="http://www.antdv.com" type="canvas" />
20+
<a-qrcode value="http://www.antdv.com" type="svg" />
21+
</a-space>
22+
</template>

components/qrcode/demo/download.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ A way to download QRCode.
1515
</docs>
1616

1717
<template>
18-
<a-qrcode ref="qrcodeCanvasRef" value="http://www.antv.com" />
18+
<a-qrcode ref="qrcodeCanvasRef" value="http://www.antdv.com" />
1919
<br />
2020
<br />
2121
<a-button type="primary" @click="dowloadChange">Downlaod</a-button>

components/qrcode/demo/icon.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ QRCode with Icon.
1717
<template>
1818
<a-qrcode
1919
error-level="H"
20-
value="https://www.antv.com"
20+
value="https://www.antdv.com"
2121
icon="https://www.antdv.com/assets/logo.1ef800a8.svg"
2222
/>
2323
</template>

components/qrcode/demo/index.vue

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<Base />
44
<Icon />
55
<Status />
6+
<CustomType />
67
<CustomSize />
78
<CustomColor />
89
<Download />
@@ -23,9 +24,20 @@ import CustomColor from './customColor.vue';
2324
import Download from './download.vue';
2425
import ErrorLevel from './errorLevel.vue';
2526
import Popover from './popover.vue';
27+
import CustomType from './customType.vue';
2628
2729
export default defineComponent({
28-
components: { Base, Icon, Status, CustomSize, CustomColor, Download, ErrorLevel, Popover },
30+
components: {
31+
Base,
32+
Icon,
33+
Status,
34+
CustomSize,
35+
CustomColor,
36+
Download,
37+
ErrorLevel,
38+
Popover,
39+
CustomType,
40+
},
2941
category: 'Components',
3042
subtitle: '二维码',
3143
type: 'Data Display',

components/qrcode/demo/popover.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ With Popover.
1515
</docs>
1616

1717
<template>
18-
<a-popover>
18+
<a-popover :overlay-inner-style="{ padding: 0 }">
1919
<template #content>
20-
<a-qrcode value="http://www.antv.com" />
20+
<a-qrcode value="http://www.antdv.com" :bordered="false" />
2121
</template>
2222
<img width="100" height="100" src="https://aliyuncdn.antdv.com/logo.png" />
2323
</a-popover>

components/qrcode/demo/status.vue

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ The status can be controlled by the value `status`.
1616

1717
<template>
1818
<a-space>
19-
<div><a-qrcode value="http://www.antv.com" status="loading" /></div>
20-
<div><a-qrcode value="http://www.antv.com" status="expired" @refresh="refreshChange" /></div>
19+
<a-qrcode value="http://www.antdv.com" status="loading" />
20+
<a-qrcode
21+
value="http://www.antdv.com"
22+
status="expired"
23+
@refresh="() => console.log('refresh')"
24+
/>
2125
</a-space>
2226
</template>
23-
24-
<script lang="ts" setup>
25-
const refreshChange = () => alert('updated');
26-
</script>

components/qrcode/index.en-US.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ Used when the link needs to be converted into a QR Code.
1515
| Property | Description | Type | Default |
1616
| --- | --- | --- | --- |
1717
| value | scanned link | string | - |
18+
| type | render type | `'canvas'` \| `'svg'` | `canvas` |
1819
| icon | include image url (only image link are supported) | string | - |
1920
| size | QRCode size | number | 128 |
2021
| iconSize | include image size | number | 32 |
2122
| color | QRCode Color | string | `#000` |
23+
| bgColor | QRCode Background Color | string | `transparent` |
2224
| bordered | Whether has border style | boolean | `true` |
2325
| errorLevel | Error Code Level | `'L'` \| `'M'` \| `'Q'` \| `'H'` | `'M'` |
2426
| status | QRCode status | `active` \| `expired` \| `loading ` | `active` |

components/qrcode/index.tsx

+15-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Spin from '../spin';
88
import Button from '../button';
99
import { ReloadOutlined } from '@ant-design/icons-vue';
1010
import { useToken } from '../theme/internal';
11-
import { QRCodeCanvas } from './QRCodeCanvas';
11+
import { QRCodeCanvas, QRCodeSVG } from './QRCode';
1212
import warning from '../_util/warning';
1313
import { qrcodeProps } from './interface';
1414

@@ -42,7 +42,8 @@ const QRCode = defineComponent({
4242
icon = '',
4343
size = 160,
4444
iconSize = 40,
45-
color = '#000',
45+
color = token.value.colorText,
46+
bgColor = 'transparent',
4647
errorLevel = 'M',
4748
} = props;
4849
const imageSettings: QRCodeProps['imageSettings'] = {
@@ -57,7 +58,7 @@ const QRCode = defineComponent({
5758
value,
5859
size: size - (token.value.paddingSM + token.value.lineWidth) * 2,
5960
level: errorLevel,
60-
bgColor: 'transparent',
61+
bgColor,
6162
fgColor: color,
6263
imageSettings: icon ? imageSettings : undefined,
6364
};
@@ -69,13 +70,17 @@ const QRCode = defineComponent({
6970
{...attrs}
7071
style={[
7172
attrs.style as CSSProperties,
72-
{ width: props.size + 'px', height: props.size + 'px' },
73+
{
74+
width: `${props.size}px`,
75+
height: `${props.size}px`,
76+
backgroundColor: qrCodeProps.value.bgColor,
77+
},
7378
]}
7479
class={[
7580
hashId.value,
7681
pre,
7782
{
78-
[`${prefixCls}-borderless`]: !props.bordered,
83+
[`${pre}-borderless`]: !props.bordered,
7984
},
8085
]}
8186
>
@@ -96,7 +101,11 @@ const QRCode = defineComponent({
96101
)}
97102
</div>
98103
)}
99-
<QRCodeCanvas ref={qrCodeCanvas} {...qrCodeProps.value} />
104+
{props.type === 'canvas' ? (
105+
<QRCodeCanvas ref={qrCodeCanvas} {...qrCodeProps.value} />
106+
) : (
107+
<QRCodeSVG {...qrCodeProps.value} />
108+
)}
100109
</div>,
101110
);
102111
};

components/qrcode/index.zh-CN.md

+2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*M4PBTZ_n9OgAAA
1616
| 参数 | 说明 | 类型 | 默认值 |
1717
| --- | --- | --- | --- |
1818
| value | 扫描后的地址 | string | - |
19+
| type | 渲染类型 | `'canvas'` \| `'svg'` | `canvas` |
1920
| icon | 二维码中图片的地址(目前只支持图片地址) | string | - |
2021
| size | 二维码大小 | number | 160 |
2122
| iconSize | 二维码中图片的大小 | number | 40 |
2223
| color | 二维码颜色 | string | `#000` |
24+
| bgColor | 二维码背景颜色 | string | `transparent` |
2325
| bordered | 是否有边框 | boolean | `true` |
2426
| errorLevel | 二维码纠错等级 | `'L'` \| `'M'` \| `'Q'` \| `'H'` | `'M'` |
2527
| status | 二维码状态 | `active` \| `expired` \| `loading ` | `active` |

components/qrcode/interface.ts

+2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ export const qrProps = () => {
1212
return {
1313
size: { type: Number, default: 160 },
1414
value: { type: String, required: true },
15+
type: stringType<'canvas' | 'svg'>('canvas'),
1516
color: String,
17+
bgColor: String,
1618
includeMargin: Boolean,
1719
imageSettings: objectType<ImageSettings>(),
1820
};

0 commit comments

Comments
 (0)