使用 Yup 和 formik 验证图像的纵横比 (width/height)
Validating image's aspect ratio (width/height) with Yup & formik
我正在尝试使用 yup 对图像文件进行验证,我发现 https://github.com/formium/formik/issues/926 仅验证大小和文件类型。
这是我目前使用的 yup 验证
file: lazy(value => {
switch (typeof value) {
case 'string':
return string().required(errorHandler.requiredFile());
default:
return mixed()
.required(errorHandler.requiredFile())
.test(
'fileSize',
'Size',
value => value && value.size <= FILE_SIZE
)
.test(
'fileType',
'Format',
value => value && SUPPORTED_FORMATS.includes(value.type)
)
}
}),
我该怎么做?
我用这个函数成功做到了
function checkAspectRatio(value) {
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(value);
reader.onload = function(value) {
const img = new Image();
img.src = value.target.result;
img.onload = function() {
const aspectRatio = this.width / this.height;
resolve(aspectRatio);
};
};
});
}
使用 Object.defineProperty()
在对象上定义一个新的 属性
Object.defineProperty(file, 'aspectRatio', {
value: await checkAspectRatio(file)
});
并使用 yup
测试值
.test(
'fileAspectRatio',
'Please recheck the image resolution',
value => value && value.aspectRatio === 1.6
);
image: Yup.mixed()
.required("Image is required.")
.test(
"aspectRatio",
"Aspect ratio must be 16:9",
value => {
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(value[0]);
reader.onload = function(value) {
const img = new Image();
img.src = value.target.result;
img.onload = function() {
const aspectRatio = this.width / this.height;
resolve(aspectRatio === (16 / 9));
};
};
});
}
),
这里有两种替代方法,比(反)编码 to/from base64 更快,并且不需要文件读取器
function checkAspectRatio (file) {
const img = new Image()
img.src = URL.createObjectURL(file)
return img.decode().then(() => {
URL.revokeObjectURL(img.src)
return img.width / img.height
})
}
// not as cross compatible
function checkAspectRatio (file) {
return createImageBitmap(file)
.then(bitmap => bitmap.width / bitmap.height)
}
- 创建一个将加载图像文件和return维度的承诺
const imageWidthAndHeight = (provideFile) => {
// take the given file (which should be an image) and return the width and height
const imgDimensions = { width: null, height: null };
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(provideFile);
reader.onload = function () {
const img = new Image();
img.src = reader.result;
img.onload = function () {
imgDimensions.width = img.width;
imgDimensions.height = img.height;
resolve(imgDimensions);
}
};
});
}
- 在自定义 yup 函数中调用并等待 promise(使用 addMethod)并添加额外的验证以检查宽度和高度。
const imageDimensionCheck = Yup.addMethod(Yup.mixed, 'imageDimensionCheck', function (message, requiredWidth, requiredHeight) {
return this.test("image-width-height-check", message, async function (value) {
const { path, createError } = this;
if (!value) {
return;
}
const imgDimensions = await imageWidthAndHeight(value);
if (imgDimensions.width !== requiredWidth) {
return createError({
path,
message: `The file width needs to be the ${requiredWidth}px!`
});
}
if (imgDimensions.height !== requiredHeight) {
return createError({
path,
message: `The file height needs to be the ${requiredHeight}px!`
});
}
return true;
});
});
- 在formik中调用创建的Yup方法
<Formik
initialValues={{
bookCoverPhoto: null,
}}
validationSchema={
Yup.object().shape({
bookCoverPhoto: Yup.mixed()
.required('You need to provide a file')
.imageDimensionCheck('test', 1988, 3056)
})
}
>
....Stuff
</Formik>
我正在尝试使用 yup 对图像文件进行验证,我发现 https://github.com/formium/formik/issues/926 仅验证大小和文件类型。
这是我目前使用的 yup 验证
file: lazy(value => {
switch (typeof value) {
case 'string':
return string().required(errorHandler.requiredFile());
default:
return mixed()
.required(errorHandler.requiredFile())
.test(
'fileSize',
'Size',
value => value && value.size <= FILE_SIZE
)
.test(
'fileType',
'Format',
value => value && SUPPORTED_FORMATS.includes(value.type)
)
}
}),
我该怎么做?
我用这个函数成功做到了
function checkAspectRatio(value) {
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(value);
reader.onload = function(value) {
const img = new Image();
img.src = value.target.result;
img.onload = function() {
const aspectRatio = this.width / this.height;
resolve(aspectRatio);
};
};
});
}
使用 Object.defineProperty()
在对象上定义一个新的 属性
Object.defineProperty(file, 'aspectRatio', {
value: await checkAspectRatio(file)
});
并使用 yup
测试值.test(
'fileAspectRatio',
'Please recheck the image resolution',
value => value && value.aspectRatio === 1.6
);
image: Yup.mixed()
.required("Image is required.")
.test(
"aspectRatio",
"Aspect ratio must be 16:9",
value => {
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(value[0]);
reader.onload = function(value) {
const img = new Image();
img.src = value.target.result;
img.onload = function() {
const aspectRatio = this.width / this.height;
resolve(aspectRatio === (16 / 9));
};
};
});
}
),
这里有两种替代方法,比(反)编码 to/from base64 更快,并且不需要文件读取器
function checkAspectRatio (file) {
const img = new Image()
img.src = URL.createObjectURL(file)
return img.decode().then(() => {
URL.revokeObjectURL(img.src)
return img.width / img.height
})
}
// not as cross compatible
function checkAspectRatio (file) {
return createImageBitmap(file)
.then(bitmap => bitmap.width / bitmap.height)
}
- 创建一个将加载图像文件和return维度的承诺
const imageWidthAndHeight = (provideFile) => {
// take the given file (which should be an image) and return the width and height
const imgDimensions = { width: null, height: null };
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(provideFile);
reader.onload = function () {
const img = new Image();
img.src = reader.result;
img.onload = function () {
imgDimensions.width = img.width;
imgDimensions.height = img.height;
resolve(imgDimensions);
}
};
});
}
- 在自定义 yup 函数中调用并等待 promise(使用 addMethod)并添加额外的验证以检查宽度和高度。
const imageDimensionCheck = Yup.addMethod(Yup.mixed, 'imageDimensionCheck', function (message, requiredWidth, requiredHeight) {
return this.test("image-width-height-check", message, async function (value) {
const { path, createError } = this;
if (!value) {
return;
}
const imgDimensions = await imageWidthAndHeight(value);
if (imgDimensions.width !== requiredWidth) {
return createError({
path,
message: `The file width needs to be the ${requiredWidth}px!`
});
}
if (imgDimensions.height !== requiredHeight) {
return createError({
path,
message: `The file height needs to be the ${requiredHeight}px!`
});
}
return true;
});
});
- 在formik中调用创建的Yup方法
<Formik
initialValues={{
bookCoverPhoto: null,
}}
validationSchema={
Yup.object().shape({
bookCoverPhoto: Yup.mixed()
.required('You need to provide a file')
.imageDimensionCheck('test', 1988, 3056)
})
}
>
....Stuff
</Formik>