qrcode.vue 3.9.1 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +60 -1
- package/README.zh-hant.md +369 -0
- package/dist/index.d.ts +7 -42
- package/dist/qrcode.vue.browser.js +53 -16
- package/dist/qrcode.vue.browser.min.js +3 -3
- package/dist/qrcode.vue.cjs.js +53 -16
- package/dist/qrcode.vue.esm.js +54 -17
- package/llms.txt +30 -0
- package/package.json +13 -10
- package/skills/qrcode-vue/SKILL.md +129 -0
- package/README-zh_cn.md +0 -310
package/dist/qrcode.vue.cjs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* qrcode.vue v3.
|
|
2
|
+
* qrcode.vue v3.11.0
|
|
3
3
|
* A Vue.js component to generate QRCode. Both support Vue 2 and Vue 3
|
|
4
4
|
* © 2017-PRESENT @scopewu(https://github.com/scopewu)
|
|
5
|
-
* MIT
|
|
5
|
+
* @license MIT.
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
@@ -1073,6 +1073,14 @@ function useQRCode(props) {
|
|
|
1073
1073
|
});
|
|
1074
1074
|
return { margin: margin, numCells: numCells, cells: cells, fgPath: fgPath, imageProps: imageProps, imageBorderProps: imageBorderProps };
|
|
1075
1075
|
}
|
|
1076
|
+
function downloadDataURLAsFile(data, filename) {
|
|
1077
|
+
var link = document.createElement('a');
|
|
1078
|
+
link.download = filename;
|
|
1079
|
+
link.href = data;
|
|
1080
|
+
document.body.appendChild(link);
|
|
1081
|
+
link.click();
|
|
1082
|
+
document.body.removeChild(link);
|
|
1083
|
+
}
|
|
1076
1084
|
var QRCodeProps = {
|
|
1077
1085
|
value: {
|
|
1078
1086
|
type: String,
|
|
@@ -1098,38 +1106,32 @@ var QRCodeProps = {
|
|
|
1098
1106
|
},
|
|
1099
1107
|
margin: {
|
|
1100
1108
|
type: Number,
|
|
1101
|
-
required: false,
|
|
1102
1109
|
default: DEFAULT_MARGIN,
|
|
1110
|
+
validator: function (m) { return m >= 0; },
|
|
1103
1111
|
},
|
|
1104
1112
|
imageSettings: {
|
|
1105
1113
|
type: Object,
|
|
1106
|
-
required: false,
|
|
1107
1114
|
default: function () { return ({}); },
|
|
1108
1115
|
},
|
|
1109
1116
|
gradient: {
|
|
1110
1117
|
type: Boolean,
|
|
1111
|
-
required: false,
|
|
1112
1118
|
default: false,
|
|
1113
1119
|
},
|
|
1114
1120
|
gradientType: {
|
|
1115
1121
|
type: String,
|
|
1116
|
-
required: false,
|
|
1117
1122
|
default: 'linear',
|
|
1118
1123
|
validator: function (t) { return ['linear', 'radial'].indexOf(t) > -1; },
|
|
1119
1124
|
},
|
|
1120
1125
|
gradientStartColor: {
|
|
1121
1126
|
type: String,
|
|
1122
|
-
required: false,
|
|
1123
1127
|
default: '#000',
|
|
1124
1128
|
},
|
|
1125
1129
|
gradientEndColor: {
|
|
1126
1130
|
type: String,
|
|
1127
|
-
required: false,
|
|
1128
1131
|
default: '#fff',
|
|
1129
1132
|
},
|
|
1130
1133
|
radius: {
|
|
1131
1134
|
type: Number,
|
|
1132
|
-
required: false,
|
|
1133
1135
|
default: 0,
|
|
1134
1136
|
validator: function (r) { return !isNaN(r) && r >= 0 && r <= 0.5; },
|
|
1135
1137
|
},
|
|
@@ -1147,8 +1149,9 @@ var QRCodeVueProps = __assign(__assign({}, QRCodeProps), { renderAs: {
|
|
|
1147
1149
|
var QrcodeSvg = vue.defineComponent({
|
|
1148
1150
|
name: 'QRCodeSvg',
|
|
1149
1151
|
props: QRCodeProps,
|
|
1150
|
-
setup: function (props) {
|
|
1152
|
+
setup: function (props, ctx) {
|
|
1151
1153
|
var _a = useQRCode(props), numCells = _a.numCells, fgPath = _a.fgPath, imageProps = _a.imageProps, imageBorderProps = _a.imageBorderProps;
|
|
1154
|
+
var svgEl = vue.ref();
|
|
1152
1155
|
var uid = getUid(props.id);
|
|
1153
1156
|
var qrGradientId = "qrcode.vue-gradient-".concat(uid);
|
|
1154
1157
|
var qrLogoClipPathId = "qrcode.vue-logo-clip-path-".concat(uid);
|
|
@@ -1197,15 +1200,32 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1197
1200
|
}),
|
|
1198
1201
|
]);
|
|
1199
1202
|
});
|
|
1203
|
+
var getSvgDataURL = function (svg) { return 'data:image/svg+xml;charset=utf-8,' +
|
|
1204
|
+
encodeURIComponent('<?xml version="1.0" standalone="no"?>' + new XMLSerializer().serializeToString(svg)); };
|
|
1205
|
+
ctx.expose({
|
|
1206
|
+
toDataURL: function () {
|
|
1207
|
+
var svg = svgEl.value;
|
|
1208
|
+
if (!svg)
|
|
1209
|
+
return;
|
|
1210
|
+
return getSvgDataURL(svg);
|
|
1211
|
+
},
|
|
1212
|
+
download: function (filename) {
|
|
1213
|
+
if (filename === void 0) { filename = 'qrcode.svg'; }
|
|
1214
|
+
var svg = svgEl.value;
|
|
1215
|
+
if (!svg)
|
|
1216
|
+
return;
|
|
1217
|
+
downloadDataURLAsFile(getSvgDataURL(svg), filename);
|
|
1218
|
+
},
|
|
1219
|
+
});
|
|
1200
1220
|
return function () { return vue.h('svg', {
|
|
1221
|
+
ref: svgEl,
|
|
1201
1222
|
width: props.size,
|
|
1202
1223
|
height: props.size,
|
|
1203
1224
|
xmlns: 'http://www.w3.org/2000/svg',
|
|
1204
1225
|
viewBox: "0 0 ".concat(numCells.value, " ").concat(numCells.value),
|
|
1205
1226
|
role: 'img',
|
|
1206
|
-
'aria-label': props.value,
|
|
1207
1227
|
}, [
|
|
1208
|
-
vue.h('defs', {}, [gradientVNode.value, clipPathVNode.value]),
|
|
1228
|
+
vue.h('defs', {}, [gradientVNode.value, clipPathVNode.value].filter(Boolean)),
|
|
1209
1229
|
vue.h('rect', {
|
|
1210
1230
|
width: '100%',
|
|
1211
1231
|
height: '100%',
|
|
@@ -1224,7 +1244,7 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1224
1244
|
rx: imageBorderProps.value.borderRadius,
|
|
1225
1245
|
ry: imageBorderProps.value.borderRadius,
|
|
1226
1246
|
}),
|
|
1227
|
-
props.imageSettings.src && imageProps.value && vue.h('image', __assign(
|
|
1247
|
+
props.imageSettings.src && imageProps.value && vue.h('image', __assign({ href: props.imageSettings.src, crossorigin: props.imageSettings.crossOrigin, 'clip-path': imageProps.value.borderRadius > 0 ? "url(#".concat(qrLogoClipPathId, ")") : void 0 }, imageProps.value)),
|
|
1228
1248
|
]); };
|
|
1229
1249
|
},
|
|
1230
1250
|
});
|
|
@@ -1310,12 +1330,23 @@ var QrcodeCanvas = vue.defineComponent({
|
|
|
1310
1330
|
}
|
|
1311
1331
|
};
|
|
1312
1332
|
vue.onMounted(generate);
|
|
1313
|
-
vue.watchEffect(generate);
|
|
1333
|
+
vue.watchEffect(generate, { flush: 'post' });
|
|
1334
|
+
ctx.expose({
|
|
1335
|
+
toDataURL: function (type, quality) { var _a; return (_a = canvasEl.value) === null || _a === void 0 ? void 0 : _a.toDataURL(type, quality); },
|
|
1336
|
+
download: function (filename) {
|
|
1337
|
+
if (filename === void 0) { filename = 'qrcode.png'; }
|
|
1338
|
+
var canvas = canvasEl.value;
|
|
1339
|
+
if (!canvas)
|
|
1340
|
+
return;
|
|
1341
|
+
downloadDataURLAsFile(canvas.toDataURL('image/png'), filename);
|
|
1342
|
+
},
|
|
1343
|
+
});
|
|
1314
1344
|
return function () { return vue.h(vue.Fragment, [
|
|
1315
|
-
vue.h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, role: 'img',
|
|
1345
|
+
vue.h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, role: 'img', style: __assign(__assign({}, ctx.attrs.style), { width: "".concat(props.size, "px"), height: "".concat(props.size, "px") }) })),
|
|
1316
1346
|
props.imageSettings.src && vue.h('img', {
|
|
1317
1347
|
ref: imageEl,
|
|
1318
1348
|
src: props.imageSettings.src,
|
|
1349
|
+
crossorigin: props.imageSettings.crossOrigin,
|
|
1319
1350
|
style: { display: 'none' },
|
|
1320
1351
|
onLoad: generate,
|
|
1321
1352
|
})
|
|
@@ -1325,8 +1356,14 @@ var QrcodeCanvas = vue.defineComponent({
|
|
|
1325
1356
|
var QrcodeVue = vue.defineComponent({
|
|
1326
1357
|
name: 'Qrcode',
|
|
1327
1358
|
props: QRCodeVueProps,
|
|
1328
|
-
setup: function (props) {
|
|
1359
|
+
setup: function (props, ctx) {
|
|
1360
|
+
var childRef = vue.ref();
|
|
1361
|
+
ctx.expose({
|
|
1362
|
+
toDataURL: function (type, quality) { var _a, _b; return (_b = (_a = childRef.value) === null || _a === void 0 ? void 0 : _a.toDataURL) === null || _b === void 0 ? void 0 : _b.call(_a, type, quality); },
|
|
1363
|
+
download: function (filename) { var _a, _b; return (_b = (_a = childRef.value) === null || _a === void 0 ? void 0 : _a.download) === null || _b === void 0 ? void 0 : _b.call(_a, filename); },
|
|
1364
|
+
});
|
|
1329
1365
|
return function () { return vue.h(props.renderAs === 'svg' ? QrcodeSvg : QrcodeCanvas, {
|
|
1366
|
+
ref: childRef,
|
|
1330
1367
|
value: props.value,
|
|
1331
1368
|
size: props.size,
|
|
1332
1369
|
margin: props.margin,
|
package/dist/qrcode.vue.esm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* qrcode.vue v3.
|
|
2
|
+
* qrcode.vue v3.11.0
|
|
3
3
|
* A Vue.js component to generate QRCode. Both support Vue 2 and Vue 3
|
|
4
4
|
* © 2017-PRESENT @scopewu(https://github.com/scopewu)
|
|
5
|
-
* MIT
|
|
5
|
+
* @license MIT.
|
|
6
6
|
*/
|
|
7
|
-
import { defineComponent, computed, h,
|
|
7
|
+
import { defineComponent, ref, computed, h, onMounted, watchEffect, Fragment } from 'vue';
|
|
8
8
|
|
|
9
9
|
/******************************************************************************
|
|
10
10
|
Copyright (c) Microsoft Corporation.
|
|
@@ -1069,6 +1069,14 @@ function useQRCode(props) {
|
|
|
1069
1069
|
});
|
|
1070
1070
|
return { margin: margin, numCells: numCells, cells: cells, fgPath: fgPath, imageProps: imageProps, imageBorderProps: imageBorderProps };
|
|
1071
1071
|
}
|
|
1072
|
+
function downloadDataURLAsFile(data, filename) {
|
|
1073
|
+
var link = document.createElement('a');
|
|
1074
|
+
link.download = filename;
|
|
1075
|
+
link.href = data;
|
|
1076
|
+
document.body.appendChild(link);
|
|
1077
|
+
link.click();
|
|
1078
|
+
document.body.removeChild(link);
|
|
1079
|
+
}
|
|
1072
1080
|
var QRCodeProps = {
|
|
1073
1081
|
value: {
|
|
1074
1082
|
type: String,
|
|
@@ -1094,38 +1102,32 @@ var QRCodeProps = {
|
|
|
1094
1102
|
},
|
|
1095
1103
|
margin: {
|
|
1096
1104
|
type: Number,
|
|
1097
|
-
required: false,
|
|
1098
1105
|
default: DEFAULT_MARGIN,
|
|
1106
|
+
validator: function (m) { return m >= 0; },
|
|
1099
1107
|
},
|
|
1100
1108
|
imageSettings: {
|
|
1101
1109
|
type: Object,
|
|
1102
|
-
required: false,
|
|
1103
1110
|
default: function () { return ({}); },
|
|
1104
1111
|
},
|
|
1105
1112
|
gradient: {
|
|
1106
1113
|
type: Boolean,
|
|
1107
|
-
required: false,
|
|
1108
1114
|
default: false,
|
|
1109
1115
|
},
|
|
1110
1116
|
gradientType: {
|
|
1111
1117
|
type: String,
|
|
1112
|
-
required: false,
|
|
1113
1118
|
default: 'linear',
|
|
1114
1119
|
validator: function (t) { return ['linear', 'radial'].indexOf(t) > -1; },
|
|
1115
1120
|
},
|
|
1116
1121
|
gradientStartColor: {
|
|
1117
1122
|
type: String,
|
|
1118
|
-
required: false,
|
|
1119
1123
|
default: '#000',
|
|
1120
1124
|
},
|
|
1121
1125
|
gradientEndColor: {
|
|
1122
1126
|
type: String,
|
|
1123
|
-
required: false,
|
|
1124
1127
|
default: '#fff',
|
|
1125
1128
|
},
|
|
1126
1129
|
radius: {
|
|
1127
1130
|
type: Number,
|
|
1128
|
-
required: false,
|
|
1129
1131
|
default: 0,
|
|
1130
1132
|
validator: function (r) { return !isNaN(r) && r >= 0 && r <= 0.5; },
|
|
1131
1133
|
},
|
|
@@ -1143,8 +1145,9 @@ var QRCodeVueProps = __assign(__assign({}, QRCodeProps), { renderAs: {
|
|
|
1143
1145
|
var QrcodeSvg = defineComponent({
|
|
1144
1146
|
name: 'QRCodeSvg',
|
|
1145
1147
|
props: QRCodeProps,
|
|
1146
|
-
setup: function (props) {
|
|
1148
|
+
setup: function (props, ctx) {
|
|
1147
1149
|
var _a = useQRCode(props), numCells = _a.numCells, fgPath = _a.fgPath, imageProps = _a.imageProps, imageBorderProps = _a.imageBorderProps;
|
|
1150
|
+
var svgEl = ref();
|
|
1148
1151
|
var uid = getUid(props.id);
|
|
1149
1152
|
var qrGradientId = "qrcode.vue-gradient-".concat(uid);
|
|
1150
1153
|
var qrLogoClipPathId = "qrcode.vue-logo-clip-path-".concat(uid);
|
|
@@ -1193,15 +1196,32 @@ var QrcodeSvg = defineComponent({
|
|
|
1193
1196
|
}),
|
|
1194
1197
|
]);
|
|
1195
1198
|
});
|
|
1199
|
+
var getSvgDataURL = function (svg) { return 'data:image/svg+xml;charset=utf-8,' +
|
|
1200
|
+
encodeURIComponent('<?xml version="1.0" standalone="no"?>' + new XMLSerializer().serializeToString(svg)); };
|
|
1201
|
+
ctx.expose({
|
|
1202
|
+
toDataURL: function () {
|
|
1203
|
+
var svg = svgEl.value;
|
|
1204
|
+
if (!svg)
|
|
1205
|
+
return;
|
|
1206
|
+
return getSvgDataURL(svg);
|
|
1207
|
+
},
|
|
1208
|
+
download: function (filename) {
|
|
1209
|
+
if (filename === void 0) { filename = 'qrcode.svg'; }
|
|
1210
|
+
var svg = svgEl.value;
|
|
1211
|
+
if (!svg)
|
|
1212
|
+
return;
|
|
1213
|
+
downloadDataURLAsFile(getSvgDataURL(svg), filename);
|
|
1214
|
+
},
|
|
1215
|
+
});
|
|
1196
1216
|
return function () { return h('svg', {
|
|
1217
|
+
ref: svgEl,
|
|
1197
1218
|
width: props.size,
|
|
1198
1219
|
height: props.size,
|
|
1199
1220
|
xmlns: 'http://www.w3.org/2000/svg',
|
|
1200
1221
|
viewBox: "0 0 ".concat(numCells.value, " ").concat(numCells.value),
|
|
1201
1222
|
role: 'img',
|
|
1202
|
-
'aria-label': props.value,
|
|
1203
1223
|
}, [
|
|
1204
|
-
h('defs', {}, [gradientVNode.value, clipPathVNode.value]),
|
|
1224
|
+
h('defs', {}, [gradientVNode.value, clipPathVNode.value].filter(Boolean)),
|
|
1205
1225
|
h('rect', {
|
|
1206
1226
|
width: '100%',
|
|
1207
1227
|
height: '100%',
|
|
@@ -1220,7 +1240,7 @@ var QrcodeSvg = defineComponent({
|
|
|
1220
1240
|
rx: imageBorderProps.value.borderRadius,
|
|
1221
1241
|
ry: imageBorderProps.value.borderRadius,
|
|
1222
1242
|
}),
|
|
1223
|
-
props.imageSettings.src && imageProps.value && h('image', __assign(
|
|
1243
|
+
props.imageSettings.src && imageProps.value && h('image', __assign({ href: props.imageSettings.src, crossorigin: props.imageSettings.crossOrigin, 'clip-path': imageProps.value.borderRadius > 0 ? "url(#".concat(qrLogoClipPathId, ")") : void 0 }, imageProps.value)),
|
|
1224
1244
|
]); };
|
|
1225
1245
|
},
|
|
1226
1246
|
});
|
|
@@ -1306,12 +1326,23 @@ var QrcodeCanvas = defineComponent({
|
|
|
1306
1326
|
}
|
|
1307
1327
|
};
|
|
1308
1328
|
onMounted(generate);
|
|
1309
|
-
watchEffect(generate);
|
|
1329
|
+
watchEffect(generate, { flush: 'post' });
|
|
1330
|
+
ctx.expose({
|
|
1331
|
+
toDataURL: function (type, quality) { var _a; return (_a = canvasEl.value) === null || _a === void 0 ? void 0 : _a.toDataURL(type, quality); },
|
|
1332
|
+
download: function (filename) {
|
|
1333
|
+
if (filename === void 0) { filename = 'qrcode.png'; }
|
|
1334
|
+
var canvas = canvasEl.value;
|
|
1335
|
+
if (!canvas)
|
|
1336
|
+
return;
|
|
1337
|
+
downloadDataURLAsFile(canvas.toDataURL('image/png'), filename);
|
|
1338
|
+
},
|
|
1339
|
+
});
|
|
1310
1340
|
return function () { return h(Fragment, [
|
|
1311
|
-
h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, role: 'img',
|
|
1341
|
+
h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, role: 'img', style: __assign(__assign({}, ctx.attrs.style), { width: "".concat(props.size, "px"), height: "".concat(props.size, "px") }) })),
|
|
1312
1342
|
props.imageSettings.src && h('img', {
|
|
1313
1343
|
ref: imageEl,
|
|
1314
1344
|
src: props.imageSettings.src,
|
|
1345
|
+
crossorigin: props.imageSettings.crossOrigin,
|
|
1315
1346
|
style: { display: 'none' },
|
|
1316
1347
|
onLoad: generate,
|
|
1317
1348
|
})
|
|
@@ -1321,8 +1352,14 @@ var QrcodeCanvas = defineComponent({
|
|
|
1321
1352
|
var QrcodeVue = defineComponent({
|
|
1322
1353
|
name: 'Qrcode',
|
|
1323
1354
|
props: QRCodeVueProps,
|
|
1324
|
-
setup: function (props) {
|
|
1355
|
+
setup: function (props, ctx) {
|
|
1356
|
+
var childRef = ref();
|
|
1357
|
+
ctx.expose({
|
|
1358
|
+
toDataURL: function (type, quality) { var _a, _b; return (_b = (_a = childRef.value) === null || _a === void 0 ? void 0 : _a.toDataURL) === null || _b === void 0 ? void 0 : _b.call(_a, type, quality); },
|
|
1359
|
+
download: function (filename) { var _a, _b; return (_b = (_a = childRef.value) === null || _a === void 0 ? void 0 : _a.download) === null || _b === void 0 ? void 0 : _b.call(_a, filename); },
|
|
1360
|
+
});
|
|
1325
1361
|
return function () { return h(props.renderAs === 'svg' ? QrcodeSvg : QrcodeCanvas, {
|
|
1362
|
+
ref: childRef,
|
|
1326
1363
|
value: props.value,
|
|
1327
1364
|
size: props.size,
|
|
1328
1365
|
margin: props.margin,
|
package/llms.txt
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# qrcode.vue
|
|
2
|
+
|
|
3
|
+
> A Vue.js component to generate QR codes. Version 3.x supports Vue 3 (peer dependency `vue@^3.0.0`, no runtime dependencies); Vue 2 apps use qrcode.vue 1.x. Renders to `<canvas>` or `<svg>`, with gradients, rounded modules, and embedded logo images. MIT licensed.
|
|
4
|
+
|
|
5
|
+
Install: `npm install --save qrcode.vue`
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import QrcodeVue, { QrcodeCanvas, QrcodeSvg } from 'qrcode.vue'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Key props: `value` (required), `size` (default 100), `render-as` (`canvas`|`svg`, svg works on SSR), `level` (L/M/Q/H, default L), `margin`, `background`/`foreground`, `gradient` + `gradient-type` + `gradient-start-color`/`gradient-end-color`, `radius` (0–0.5 rounded modules), `image-settings` (embedded logo: `src`, `x`/`y`, `width`/`height`, `excavate`, `borderRadius`, `crossOrigin`), `id` (SSR-safe internal SVG ids, pass `useId()`). Template-ref methods: `toDataURL()`, `download(filename)`.
|
|
12
|
+
|
|
13
|
+
## Docs
|
|
14
|
+
|
|
15
|
+
- [README (English)](https://github.com/scopewu/qrcode.vue/blob/main/README.md): install, usage, full props reference, template ref methods
|
|
16
|
+
- [README (简体中文)](https://github.com/scopewu/qrcode.vue/blob/main/README-zh_cn.md)
|
|
17
|
+
- [README (繁體中文)](https://github.com/scopewu/qrcode.vue/blob/main/README.zh-hant.md)
|
|
18
|
+
- [README (日本語)](https://github.com/scopewu/qrcode.vue/blob/main/README-ja.md)
|
|
19
|
+
- [CHANGELOG](https://github.com/scopewu/qrcode.vue/blob/main/CHANGELOG.md): version history and breaking changes
|
|
20
|
+
|
|
21
|
+
## AI assistant resources
|
|
22
|
+
|
|
23
|
+
- [SKILL.md](https://github.com/scopewu/qrcode.vue/blob/main/skills/qrcode-vue/SKILL.md): Agent Skills–format skill with props table, recipes, and pitfalls. Also shipped in the npm package at `node_modules/qrcode.vue/skills/qrcode-vue/SKILL.md`.
|
|
24
|
+
- [Live demo](https://qr-vue.tie.pub): interactive playground for all props
|
|
25
|
+
|
|
26
|
+
## Source
|
|
27
|
+
|
|
28
|
+
- [src/index.ts](https://github.com/scopewu/qrcode.vue/blob/main/src/index.ts): the whole library — components, props, exported types (`Level`, `RenderAs`, `GradientType`, `ImageSettings`)
|
|
29
|
+
- [npm package](https://www.npmjs.com/package/qrcode.vue)
|
|
30
|
+
- [Repository](https://github.com/scopewu/qrcode.vue)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qrcode.vue",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "A Vue.js component to generate QRCode. Both support Vue 2 and Vue 3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/qrcode.vue.cjs.js",
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
"./package": "./package.json"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"dev": "rsbuild dev",
|
|
21
|
+
"dev": "node example/scripts/generate-i18n.js && rsbuild dev",
|
|
22
22
|
"build": "rollup -c",
|
|
23
|
+
"build:example": "node example/scripts/generate-i18n.js && rsbuild build",
|
|
24
|
+
"generate:i18n": "node example/scripts/generate-i18n.js",
|
|
23
25
|
"test": "rstest"
|
|
24
26
|
},
|
|
25
27
|
"repository": "https://github.com/scopewu/qrcode.vue.git",
|
|
@@ -34,9 +36,10 @@
|
|
|
34
36
|
],
|
|
35
37
|
"files": [
|
|
36
38
|
"/dist",
|
|
39
|
+
"/skills",
|
|
37
40
|
"CHANGELOG.md",
|
|
38
|
-
"README
|
|
39
|
-
"
|
|
41
|
+
"README.md",
|
|
42
|
+
"llms.txt"
|
|
40
43
|
],
|
|
41
44
|
"author": "scope.wu <scope.wu@gmail.com>",
|
|
42
45
|
"license": "MIT",
|
|
@@ -50,13 +53,13 @@
|
|
|
50
53
|
"dependencies": {},
|
|
51
54
|
"devDependencies": {
|
|
52
55
|
"@rollup/plugin-terser": "^1.0.0",
|
|
53
|
-
"@rsbuild/core": "^2.
|
|
54
|
-
"@rstest/core": "^0.
|
|
55
|
-
"@vue/test-utils": "^2.
|
|
56
|
-
"happy-dom": "^20.
|
|
57
|
-
"rollup": "^4.
|
|
56
|
+
"@rsbuild/core": "^2.2.1",
|
|
57
|
+
"@rstest/core": "^0.11.10",
|
|
58
|
+
"@vue/test-utils": "^2.5.0",
|
|
59
|
+
"happy-dom": "^20.11.12",
|
|
60
|
+
"rollup": "^4.63.1",
|
|
58
61
|
"rollup-plugin-typescript2": "^0.37.0",
|
|
59
62
|
"typescript": "^5.9.3",
|
|
60
|
-
"vue": "^3.5.
|
|
63
|
+
"vue": "^3.5.42"
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qrcode-vue
|
|
3
|
+
description: Generate QR codes in Vue 3 apps with the qrcode.vue component library. Use this skill whenever the user wants to render, style, or download a QR code in Vue — including QR with a logo/image, gradient or rounded modules, SVG vs canvas output, SSR/Nuxt usage, or TypeScript typing — even if they don't name the library explicitly.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# qrcode.vue
|
|
7
|
+
|
|
8
|
+
A Vue.js component to generate QR codes. Version 3.x targets **Vue 3 only** (Vue 2 apps must use qrcode.vue 1.x). Peer dependency: `vue@^3.0.0`. No other runtime dependencies.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install --save qrcode.vue # or: yarn add qrcode.vue
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Exports
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import QrcodeVue, { QrcodeCanvas, QrcodeSvg } from 'qrcode.vue'
|
|
20
|
+
import type { Level, RenderAs, GradientType, ImageSettings } from 'qrcode.vue'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `QrcodeVue` (default) — switches between canvas and SVG via the `render-as` prop.
|
|
24
|
+
- `QrcodeCanvas` / `QrcodeSvg` (named) — single-renderer components. Prefer these when the renderer is fixed.
|
|
25
|
+
|
|
26
|
+
CommonJS / CDN note: exports are named since 3.5 — use `require('qrcode.vue').default` or `QrcodeVue.default` when loading the UMD bundle.
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
All three components share these props (`render-as` exists only on `QrcodeVue`):
|
|
31
|
+
|
|
32
|
+
| Prop | Type | Default | Notes |
|
|
33
|
+
|------|------|---------|-------|
|
|
34
|
+
| `value` | `string` | `''` | **Required.** QR content. |
|
|
35
|
+
| `size` | `number` | `100` | Element size in px. |
|
|
36
|
+
| `render-as` | `'canvas' \| 'svg'` | `'canvas'` | `QrcodeVue` only. Use `'svg'` for SSR. |
|
|
37
|
+
| `level` | `'L' \| 'M' \| 'Q' \| 'H'` | `'L'` | Error correction. Use `'H'` when embedding a logo. |
|
|
38
|
+
| `background` | `string` | `'#fff'` | Background color. |
|
|
39
|
+
| `foreground` | `string` | `'#000'` | Module color (ignored when `gradient` is on). |
|
|
40
|
+
| `margin` | `number` | `0` | Quiet-zone width in modules, `>= 0`. |
|
|
41
|
+
| `radius` | `number` | `0` | Module corner radius, `0`–`0.5`. `0.5` = circular modules. Inner corners between adjacent modules stay sharp. |
|
|
42
|
+
| `gradient` | `boolean` | `false` | Enable gradient fill. |
|
|
43
|
+
| `gradient-type` | `'linear' \| 'radial'` | `'linear'` | Gradient direction type. |
|
|
44
|
+
| `gradient-start-color` | `string` | `'#000'` | Gradient start. |
|
|
45
|
+
| `gradient-end-color` | `string` | `'#fff'` | Gradient end. |
|
|
46
|
+
| `image-settings` | `ImageSettings` | `{}` | Embedded logo, see below. |
|
|
47
|
+
| `id` | `string` | `undefined` | ID base for internal SVG defs. Pass `useId()` (Vue 3.5+) for SSR hydration safety. |
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
type ImageSettings = {
|
|
51
|
+
src: string // image URL
|
|
52
|
+
x?: number; y?: number // offset; centered when omitted
|
|
53
|
+
height?: number; width?: number // default: 10% of `size`
|
|
54
|
+
excavate?: boolean // clear modules behind the image
|
|
55
|
+
borderRadius?: number
|
|
56
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | '' // required to export canvas with a cross-origin logo
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Template ref methods
|
|
61
|
+
|
|
62
|
+
Expose `toDataURL` and `download` on all components (`QrcodeVue` forwards to the active renderer):
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<script setup>
|
|
66
|
+
import { ref } from 'vue'
|
|
67
|
+
import { QrcodeCanvas } from 'qrcode.vue'
|
|
68
|
+
|
|
69
|
+
const qrRef = ref()
|
|
70
|
+
const save = () => qrRef.value?.download('qrcode.png')
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<template>
|
|
74
|
+
<qrcode-canvas ref="qrRef" value="https://example.com" />
|
|
75
|
+
<button @click="save">Download</button>
|
|
76
|
+
</template>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- Canvas: `toDataURL(type?, quality?)`, `download(filename?)` → PNG.
|
|
80
|
+
- SVG: `toDataURL()`, `download(filename?)` → SVG.
|
|
81
|
+
|
|
82
|
+
## Recipes
|
|
83
|
+
|
|
84
|
+
QR with a centered logo — always raise `level` so the code stays scannable:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<qrcode-svg
|
|
88
|
+
value="https://example.com"
|
|
89
|
+
:size="300"
|
|
90
|
+
level="H"
|
|
91
|
+
:image-settings="{ src: logoUrl, width: 60, height: 60, excavate: true, borderRadius: 8 }"
|
|
92
|
+
/>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Gradient + rounded modules:
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<qrcode-vue
|
|
99
|
+
value="https://example.com"
|
|
100
|
+
render-as="svg"
|
|
101
|
+
gradient
|
|
102
|
+
gradient-type="radial"
|
|
103
|
+
gradient-start-color="#000000"
|
|
104
|
+
gradient-end-color="#38bdf8"
|
|
105
|
+
:radius="0.35"
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
SSR / Nuxt — render as SVG and pass a stable `id`:
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<script setup>
|
|
113
|
+
import { useId } from 'vue'
|
|
114
|
+
import { QrcodeSvg } from 'qrcode.vue'
|
|
115
|
+
const uid = useId() // Vue 3.5+; on older versions pass any unique string
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<template>
|
|
119
|
+
<qrcode-svg value="https://example.com" :id="uid" />
|
|
120
|
+
</template>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Pitfalls
|
|
124
|
+
|
|
125
|
+
- **Vue 2**: do not use 3.x — install `qrcode.vue@1.x`.
|
|
126
|
+
- **Tainted canvas**: with a cross-origin logo, set `imageSettings.crossOrigin: 'anonymous'` and ensure the image server sends `Access-Control-Allow-Origin`, or `toDataURL`/`download` throws `SecurityError`.
|
|
127
|
+
- **SSR hydration**: without an explicit `id`, internal SVG IDs come from a module-level counter and can mismatch between server and client. Always pass `useId()` under SSR.
|
|
128
|
+
- **Scannability**: keep contrast high between `foreground`/`gradient` and `background`; a logo covering too much area breaks scanning even at level `H`.
|
|
129
|
+
- **Multiple instances with gradients**: `id` keeps each SVG's `<defs>` unique; collisions cause one QR's gradient to leak into another.
|