本篇文章主要介绍一下最近的开发中用到的些小问题。问题不大,但有些小细节,记录一下,有遇到的朋友可以看一下,有更好的解决方法欢迎分享。
浏览器记住密码自动填充表单
这个问题我在火狐浏览器遇到了。我登录系统时选择了浏览器记住密码;然后在打开新建数据库弹窗,里面的户名和密码竟然自动填充了。设置了autoComplete=“off”,也没有用,这个只是为了关闭输入提示。以下时具体的解决方法,亲测有效
import React from "react";
import { Button, Form, Input } from "antd";
const MyForm: React.FC = () => {
const [form] = Form.useForm();
const onFinish = (values: any) => {
console.log("Success:", values);
};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
};
/** 清空密码 */
const resetPass = () => {
if (!form.isFieldTouched("password")) {
form.setFieldsValue({ password: "" });
}
};
/** 清空用户名 */
const resetUser = () => {
if (!form.isFieldTouched("username")) {
form.setFieldsValue({ username: "" });
}
};
return (
<Form
name="basic"
form={form}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="IP"
name="ip"
rules={[{ required: true, message: "Please input your ip!" }]}
>
<Input />
</Form.Item>
<Form.Item
label="Port"
name="port"
rules={[{ required: true, message: "Please input your port!" }]}
>
<Input />
</Form.Item>
{/* 用于干扰浏览器记住密码 */}
<Form.Item style={{ display: "none" }}>
<Input onFocus={resetUser}/>
</Form.Item>
<Form.Item style={{ display: "none" }}>
<Input.Password onFocus={resetPass}/>
</Form.Item>
<Form.Item
label="Username"
name="username"
rules={[{ required: true, message: "Please input your username!" }]}
>
<Input onFocus={resetUser} />
</Form.Item>
<Form.Item
label="Password"
name="password"
rules={[{ required: true, message: "Please input your password!" }]}
>
<Input.Password onFocus={resetPass} autoComplete="off"/>
</Form.Item>
<Form.Item wrapperCol={{ offset: 8, span: 16 }}>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
export default MyForm;
具体来说,在代码中添加了两个隐藏的<Form.Item>,一个用于用户名(Input类型),另一个用于密码(Input.Password类型),然后分别在这两个元素的onFocus事件中调用了resetUser和resetPass函数,这两个函数在字段没有被触摸(touched)过的情况下将字段值设置为空字符串。
这样的做法会使浏览器的自动填充机制失效,因为浏览器通常在填充用户凭据之前会检查字段是否为空。这是一种常见的防止浏览器自动填充密码的方法。
不过需要注意的是,浏览器的自动填充机制可能会随着时间的推移而改变,因此这种解决方案可能不是绝对稳定的。不过暂时我的页面没出现问题。
ant Design下拉框,下拉菜单、日历等组件随页面滚动问题
在antd中下拉框组件有很多比如: Select、Dropdown、DatePicker等,在点击后会出现下拉选择框,但是当滚动页面时,会发现下拉框固定不动。
分析:
-
定位问题:某些情况下,组件的定位可能会受到父元素、祖先元素的定位影响。确保你的组件的定位设置正确,可以使用 CSS 的
position
、top
、left
等属性来控制定位。 -
层叠上下文:在 CSS 中,每个元素都位于一个层叠上下文中,层叠上下文可以影响元素的渲染和布局。如果组件的父元素或祖先元素具有不同的层叠上下文属性,可能会导致组件的位置不正确。了解层叠上下文的工作原理,并适当地设置元素的
z-index
属性,可以帮助解决这类问题。 -
Fixed 定位:如果你希望组件在页面滚动时保持固定位置,可以考虑使用 CSS 中的
position: fixed
。这将使组件相对于浏览器窗口固定位置,而不受页面滚动的影响。
解决方案:
根据官方文档提供的api可以看到,有个getPopupContainer参数,可以改变下拉弹窗的渲染节点。默认是被渲染到body的,所以虽然父容器发生滚动,弹窗位置依旧不动。
import React from 'react';
import { Select } from 'antd';
const Option = Select.Option;
const Hello = () => (
<div style={{ margin: 10, overflow: 'scroll', height: 200 }}>
<h2>Select in a scrollable area</h2>
<div style={{ padding: 100, height: 1000, background: '#eee', position: 'relative' }} id="area">
<h4>可滚动的区域 / scrollable area</h4>
<Select
defaultValue="lucy"
style={{ width: 120 }}
getPopupContainer={() => document.getElementById('area')!}
>
<Option value="jack">Jack</Option>
<Option value="lucy">Lucy</Option>
<Option value="yiminghe">yiminghe</Option>
</Select>
</div>
</div>
);
export default Hello;
上面面是官网给的使用例子。就是通过id将下拉弹窗绑定到滚动区域。
这样确实能解决滚动问题,但是在滚动区域的高度或者宽度不够时,下拉弹窗的位置也会发生错位,导致样式不好看。
如果在页面高度和宽度允许的情况下,可以世道调整滚动容器的大小。由于我的下拉框时放在Modal弹窗里,滚动高度是限的,所以我使用了动态改变下拉框的渲染容器,当页面不需要滚动时就挂载到body。滚动就挂载到滚动容器上。
修改上述代码:
import React, { useRef, useState } from "react";
import { Select } from "antd";
const Option = Select.Option;
const Hello = () => {
const conRef = useRef<any>();
const [open, setOpen] = useState<boolean>(false); // 每次打开下拉框重新渲染挂载节点
/** 动态获取挂载节点 */
const getContainer = () => {
if (conRef?.current?.scrollHeight > 400) {
return conRef?.current;
}
return document.body;
};
return (
<div style={{ margin: 10, overflow: "scroll", height: 200 }}>
<h2>Select in a scrollable area</h2>
<div
style={{
padding: 100,
height: 1000,
background: "#eee",
position: "relative",
}}
id="area"
ref={conRef}
key={`${open}`}
>
<h4>可滚动的区域 / scrollable area</h4>
<Select
defaultValue="lucy"
style={{ width: 120 }}
getPopupContainer={() => getContainer()}
onDropdownVisibleChange={(e) => setOpen(e)}
>
<Option value="jack">Jack</Option>
<Option value="lucy">Lucy</Option>
<Option value="yiminghe">yiminghe</Option>
</Select>
</div>
</div>
);
};
export default Hello;
在下拉框打开时,根据滚动区域的高度决定下拉框的渲染容器,以避免下拉框的内容溢出可视区域。key={${open}} 的作用是为了在每次下拉框打开或关闭时触发一个新的 key,从而触发重新渲染。
Table 表格拖拽自适应宽度
当我在实现表格可拖拽列宽度时,有时候表格整体宽度不够时,其他列也会跟着变化。这是因为ant design 会调整列的宽度,为了解决这个问题,可以加个空白列去适应多余宽度。
类似以下代码。
ResizableTable.tsx是我根据react-resizable插件封装的Table组件。需要代码可私聊
import React from 'react';
import ResizableTable from './ResizableTable.tsx';
const columns = [
{
title: 'Name',
dataIndex: 'name',
width: 150,
},
{
title: 'Age',
dataIndex: 'age',
width: 80,
},
{
title: 'Address',
dataIndex: 'address',
width: 200,
},
{
title:'', // 用于自适应多余宽度
dataIndex:'null'
}
];
const dataSource = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
// ...more data
];
const App = () => {
return <ResizableTable columns={columns} dataSource={dataSource} />;
};
export default App;