工作踩坑系列[1]


1. img标签之object-fit属性

很简单的需求,一个上传图片的按钮,上传完毕之后把图片展示到按钮里,完成之后,我考虑到用户如果上传的图片太小或者太大,会影响视觉效果,果然在旁边做了个预览功能,方便用户放大看图,做完直接,提交代码。没多久测试提了个bug,上传的图片会拉伸,希望图片做到高保真,我一想,肯定会拉伸啊,旁边既然都有预览功能了,其实无所谓的,如图:

然后我就在思考,我要怎么在保持图片宽高比例不变的情况下,还能撑满整个按钮,没多久,我就做了个骚操作,如下

当时我都觉得完美,提交上去之后,谁都没发现问题。如下,问题一下就暴露出来了,我不去限制高度,然后宽度自适应,最后居中,完美地做了个伪高保真,后来我一想不对啊,这种内容都在中间的图片没问题,一旦图片的内容都在左侧,岂不是凉了?

后来通过研究antd上传组件,发现了object-fit这个属性,果然css还是有很多的属性不太被经常使用,所以会被忽略,平时还需要多积累积累。

object-fit:指定元素的内容应该如何去适应指定容器的高度与宽度,一般用于 img 和 video 标签,一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。

描述
fill 默认,不保证保持原有的比例,内容拉伸填充整个内容容器。
contain 保持原有尺寸比例。内容被缩放。
none 保留原有元素内容的长度和宽度,也就是说内容不会被重置
scale-down 保持原有尺寸比例。内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。
initial 设置为默认值,关于 initial
inherit 从该元素的父元素继承属性
1
2
3
4
5
6
// 最后修改代码
.ym_upload-img-list-item {
width: 100%;
height: 100%;
object-fit: contain;
}

实现效果如下,这次才是真正的完美:

2. 组件中,错误事件的传递

最近我们在开发公司自用的组件库,其实就是基于antd根据公司的业务做一层封装。

在我写的一个组件,有这样一个警告,大致就是handleChange事件并不在元素上存在

一开始我也没看出问题出在哪

1
2
3
4
// 父组件
<AreaSelect
handleChange={handleChange}
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 子组件
import RequestHelper from "@/utils/request";
import React, { useCallback, useEffect, useState } from "react";
import { Cascader } from 'antd';
import "./index.less";

const request = new RequestHelper("").jsonRequest();

interface IProps {
level?: string;
className?: string;
fieldNamesOptions?: {};
handleChange?: (value: [], selectedOptions: []) => void;
}

export const AreaSelect: React.FC<IProps> = (props: any) => {
const { handleChange, level, fieldNamesOptions, className, } = props;
const [areaData, setAreaData] = useState();
const [fieldNames] = useState(fieldNamesOptions || { label: "name", value: "code", children: "children" });

const getAreaData = useCallback(() => {
try {
request.get('/public/other/areacode', { level }).then((res) => {
const data = res?.data?.data ? res.data.data : [];
setAreaData(data);
})
} catch (e) {
console.log(e);
}
}, []);

useEffect(() => {
getAreaData();
}, []);

const onChange = useCallback((value: [], selectedOptions: []) => {
handleChange && handleChange(value, selectedOptions);
}, [handleChange]);

return (
<>
<Cascader
placeholder="请选择"
fieldNames={fieldNames}
options={areaData}
onChange={onChange}
{...props}
className={`ym_cascader ${className}`}
/>
</>
)
}
AreaSelect.defaultProps = {
level: "area",
}
export default AreaSelect;

后来经过仔细观察得到答案,问题出在我在给级联组件传递参数的时候,直接用了扩展运算符,把不属于Cascader组件的handleChange也传了过去。。。所以这里我们需要用…rest来接收属于Cascader组件的参数,把不属于他的参数过滤出来。

1
2
3
4
5
6
7
8
9
10
11
12
const { handleChange, level, fieldNamesOptions, className, ...rest } = props;
...
<>
<Cascader
placeholder="请选择"
fieldNames={fieldNames}
options={areaData}
onChange={onChange}
{...rest}
className={`ym_cascader ${className}`}
/>
</>

这里还有个需要注意的地方,就是我自定义了一个className,然后还支持传入className,如果我把他写在{…rest}前面,会被rest解构出来的className覆盖掉的,所以要⚠️一个顺序问题。

我的微信公众号: 梨的前端小屋


文章作者: 梨啊梨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 梨啊梨 !
  目录