除了直接在渲染逻辑中使用 form.getFieldValue
和 useWatch
之外,Ant Design Form
还提供了shouldUpdate属性在 Form.Item
组件上,这是另一种实现表单项之间联动的方式。shouldUpdate
允许你根据其他字段的变化来重新渲染 Form.Item
,而不需要直接操作表单状态或使用额外的状态管理。这种方法更适合于当你需要根据一个或多个表单项的值变化来改变当前表单项的行为时使用。
使用 shouldUpdate
实现表单项联动
下面是一个使用shouldUpdate
的例子,它展示了如何根据一个单选按钮的选择来显示一个额外的输入框:
import React from 'react';
import { Form, Input, Radio, Button } from 'antd';
const FormItemDependencyWithShouldUpdate = () => {
return (
<Form layout="vertical">
<Form.Item name="choice" label="选择">
<Radio.Group>
<Radio value="option1">选项1</Radio>
<Radio value="option2">选项2</Radio>
</Radio.Group>
</Form.Item>
{/* 使用shouldUpdate监听choice字段的变化 */}
<Form.Item shouldUpdate={(prevValues, currentValues) => prevValues.choice !== currentValues.choice}>
{({ getFieldValue }) => {
return getFieldValue('choice') === 'option2' ? (
<Form.Item
name="inpu
使用了 listType="picture-card"
后, 删除/上传图片父元素 .ant-upload-list-picture-card
下面会同时存在两个元素, 一个为上传触发元素, 另一个为显示图片的元素
父元素设置 overflow: hidden
来隐藏多余的元素
.ant-upload-list-picture-card {
overflow: hidden;
height: 300px; // 自行设置合适的高度
.ant-upload-select, .ant-upload-list-item-container {
width: 100% !important;
height: 100% !important;
}
}
// ElevatorScroll.vue
<template>
<div
class="elevator-container"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
ref="elevatorContainerRef"
>
<div
class="section"
v-for="(item, index) in items"
:key="item.id"
:ref="`section-${index}`"
>
<slot :item="item.list" :index="index"></slot>
</div>
<div v-if="showHint && consistentDirection" :class="['scroll-hint', hintPosition]"
:style="{ opacity: hintOpacity }">{{ hintMessage }}
</div>
</div>
</template>
<script>
export default {
props: {
items: {
type: Array,
required: true,
},
activeSectionDate: {
type: Number,
default: 0,
},
},
data() {
return {
startY: 0,
currentY: 0,
hasMoved: false, // 用于记录是否发生了有效滑动
hintOpacity: 0,
showHint: false,
hintMessage: '',
hintPosition: 'hint-bottom',
initialDirection: n
// CurrentWeekMenu.vue
<template>
<div class="CurrentWeekMenu_root">
<div class="week_box">
<div v-for="(item, index) in weekList" :key="item.id" class="week-item_box"
:class="activeSectionDate === index ? 'active' : ''" @click="scrollToSection(index)">
<div class="week-item_name">{{ item.name }}</div>
<div class="week-item_date">{{ item.date }}</div>
</div>
</div>
<div class="food-menu_box" ref="foodMenuBoxRef">
<div class="food-menu-group_box" v-for="(weekItem, weekIndex) in thisWeek" :key="weekIndex"
:id="'food-menu-group_' + weekIndex">
<div class="food-menu-item_box" v-for="item in weekItem" :key="item.id" :id="item.id"
@click="checked = !checked">
<div class="food-menu-item_img">
<van-image
width="2.13333rem"
height="1.52rem"
fit="cover"
:src="item.imgUrl"
>
const ForwardTable = React.forwardRef(InternalTable) as <RecordType extends object = any>(
props: React.PropsWithChildren<TableProps<RecordType>> & { ref?: React.Ref<HTMLDivElement> },
) => React.ReactElement;
// so u can use
<Table<{id: string, b: number}> />
type InputRefType<T> = T extends React.Ref<infer ElementType> ? ElementType : never;
const inputRef = useRef<HTMLInputElement>(null)
type MyInputRefType = InputRefType<typeof inputRef>
const a: React.MutableRefObject<MyInputRefType> = inputRef
a.current?.focus()
React
中,React.Ref
,React.RefObject
和 React.MutableRefObject
是三个不同的类型。React.Ref
是一个泛型接口,它定义了 React
元素的类型,用于表示该元素所引用的对象的类型,例如 DOM
元素和自定义组件。
React.RefObject<T>
是一个泛型类型,它是 React.Ref 的具体实现,用于引用可变的对象。它表示一个引用,该引用可以包含对某个具体对象的引用,并且可以通过 current
属性访问引用对象。在大多数情况下,当我们需要引用 DOM
元素时,我们使用 React.RefObject
。
React.MutableRefObject<T>
也是一个泛型类型,它是 React.RefObject
的子类型,它提供了一种访问当前引用的可变版本。current
属性是一个可变的对象,可以通过它来更改当前引用指向的对象。在某些情况下,例如使用 useRef 创建引用对象时,可能需要使用 React.MutableRefObject
。
综上所述,React.Ref
是一个泛型接口,React.RefObject
是它的具体实现,并且用于引用不可变对象,而 React.MutableRefObject
是 React.RefObject
的子类型,它提供了访问该引用的可变版本。通常情况下,我们使用 React.RefObject
来引用 DOM
元素,在某些情况下,可能需要使用 React.MutableRefObject
。
jsperf
jsfiddle
JSBench
JavaScript
代码片段的执行速度。 通过简单而简短的 URL
与他人在线共享和协作。测试条件 | Chrome版本94.0.4606.81 | Firefox版本93.0 (64 位) |
---|---|---|
Object.assign对象合并 | 14.07080078125 ms | 12.11 ms |
展开运算符对象合并 | 18201.126953125 ms | 7424.69 ms |
展开运算符数组加单个 | 42.848876953125 ms | 877.14 ms |
push方法数组加单个 | 0.489013671875 ms | 0.89 ms |
concat方法数组加单个 | 0.6640625 ms | 2.40 ms |
展开运算符两个大数组合并 | 38.1337890625 ms | 43.64 ms |
concat方法两个大数组合并 | 4.3740234375 ms | 31.28 ms |
在循环比较多或者操作的数组长度比较大的情况下:
Object.assign
多数情况下性能比 展开运算符(...)
的性能高connat、push
性能比 展开运算符(...)
的性能高在 Chrome版本94.0.4606.81
、 Firefox版本93.0 (64 位)
的浏览器下
Object.assign、connat
的性能会比 展开运算符“...”
的性能高Object.assign
会触发 Proxy/Object.definedProperty
的 set
方法,展开运算符“...”
不会触发Object.assign
和 展开运算符
都是浅拷贝展开运算符放在前面的性能比放在后面的性能高
function (a, ...b) {}
)的时候,有自己的使用方式展开运算符“...”
比 Object.assign
性能高getBoundingClientRect 返回的是一个 DOMRect 对象,是一组矩形集合,我们这次所使用的返回值主要是left、top、bottom和right。其余的返回值width、height、x、y这次用不到,就不再讨论。
使用方法如下:
let domToTop = dom.getBoundingClientRect().top // dom 的顶边到视口顶部的距离
let domToLeft = dom.getBoundingClientRect().left // dom 的左边到视口左边的距离
let domToBottom = dom.getBoundingClientRect().bottom // dom 的底边到视口顶部的距离
let domToRight = dom.getBoundingClientRect().right // dom 的右边到视口左边的距离
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.box {
width: 110%;
height: 200%;
position: absolute;
top: 0;
left: 0;
border: 1px solid red;
}
.content {
width: 20%;