组件 - Component
上一篇
顶层 API - F2
下一篇
画布 - Canvas
Loading...
Component 是 F2 的基础组件类,提供了完整的生命周期管理和状态管理能力。所有自定义组件都应该继承自 Component 类。
interface ComponentProps {/** 组件的层级索引 */zIndex?: number;}interface ComponentState {[key: string]: any;}interface IContext {/** 像素转换函数 */px2hd: (value: any) => any;/** 主题配置 */theme: Record<string, any>;/** 画布布局信息 */layout: LayoutProps;[key: string]: any;}interface LayoutProps {left: number;top: number;width: number;height: number;[key: string]: any;}class Component<P extends ComponentProps = ComponentProps, S = ComponentState> {/** 组件属性 */props: P;/** 组件状态 */state: S;/** 上下文对象 */context: IContext;/** 子组件引用 */refs: { [key: string]: Component };/** 更新器 */updater: Updater<S>;/** 容器 Group */container: Group;/** 布局信息 */layout: LayoutProps;/** 子组件 */children: VNode | VNode[] | null;/** 是否已挂载 */isMounted: boolean;/** 是否启用动画 */animate: boolean;/** 动画控制器 */animator: Animator;/** 是否已销毁 */destroyed: boolean;/** 虚拟 DOM 节点 */_vNode: VNode;constructor(props: P, context?: IContext);willMount(): void;didMount(): void;shouldUpdate(nextProps: P): boolean;willReceiveProps(nextProps: P, context?: IContext): void;willUpdate(): void;didUpdate(): void;render(): JSX.Element | null;willUnmount(): void;didUnmount(): void;setState(partialState: Partial<S>, callback?: () => void): void;forceUpdate(callback?: () => void): void;setAnimate(animate: boolean): void;destroy(): void;}
import { Component, jsx } from '@antv/f2';class MyComponent extends Component {willMount() {console.log('组件即将挂载');}didMount() {console.log('组件已挂载');this.setState({ count: 1 });}render() {const { state } = this;const { count = 0 } = state;return (<textstyle={{text: `Count: ${count}`,x: '50px',y: '50px',}}/>);}}
| 属性名 | 类型 | 说明 |
|---|---|---|
props | P | 组件的属性对象,由父组件传入 |
state | S | 组件的状态对象,通过 setState 更新 |
context | IContext | 组件上下文,包含 px2hd、theme、layout 等信息 |
refs | { [key: string]: Component } | 子组件引用集合 |
updater | Updater<S> | 组件更新控制器 |
container | Group | 组件的容器 Group 对象 |
layout | LayoutProps | 组件的布局信息 |
children | VNode | VNode[] | null | 组件的子节点 |
isMounted | boolean | 组件是否已挂载 |
animate | boolean | 是否启用动画 |
animator | Animator | 动画控制器 |
destroyed | boolean | 组件是否已销毁 |
_vNode | VNode | 虚拟 DOM 节点 |
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
constructor | props: P, context?: IContext | - | 构造函数,初始化组件实例 |
willMount | - | void | 组件即将挂载时调用,在 render 之前执行 |
render | - | JSX.Element | null | 渲染组件,返回 JSX 元素或 null |
didMount | - | void | 组件挂载完成后调用,可以访问 DOM 和执行副作用 |
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
willReceiveProps | nextProps: P, context?: IContext | void | 组件接收新 props 时调用,在 willMount 之前执行 |
shouldUpdate | nextProps: P | boolean | 判断组件是否需要更新,返回 false 跳过更新 |
willUpdate | - | void | 组件即将更新时调用,在 render 之前执行 |
didUpdate | - | void | 组件更新完成后调用 |
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
willUnmount | - | void | 组件即将卸载时调用,用于清理资源 |
didUnmount | - | void | 组件卸载完成后调用 |
| 方法名 | 参数 | 返回值 | 说明 |
|---|---|---|---|
setState | partialState: Partial<S>, callback?: () => void | void | 更新组件状态,触发重新渲染 |
forceUpdate | callback?: () => void | void | 强制组件更新,跳过 shouldUpdate 检查 |
setAnimate | animate: boolean | void | 设置组件是否启用动画 |
destroy | - | void | 销毁组件,清理资源 |
上下文对象提供组件运行时所需的环境信息:
| 属性名 | 类型 | 说明 |
|---|---|---|
px2hd | (value: any) => any | 像素单位转换函数,将 px 转换为高清屏单位 |
theme | Record<string, any> | 主题配置对象 |
layout | LayoutProps | 画布布局信息,包含 left、top、width、height |
创建一个简单的文本组件:
import { Component, jsx } from '@antv/f2';class TextComponent extends Component {render() {const { props } = this;const { text, x = 0, y = 0 } = props;return (<textstyle={{text,x,y,fill: '#000',fontSize: '24px',}}/>);}}
使用 setState 管理组件状态:
class Counter extends Component {constructor(props, context) {super(props, context);this.state = {count: 0,};}didMount() {// 模拟状态更新setTimeout(() => {this.setState({ count: 1 });}, 1000);}render() {const { state } = this;const { count } = state;return (<textstyle={{text: `Count: ${count}`,x: '50px',y: '50px',}}/>);}}
使用生命周期方法控制渲染流程:
class LifecycleComponent extends Component {willMount() {console.log('组件即将挂载');}didMount() {console.log('组件已挂载');// 可以在这里执行副作用,如事件绑定、数据请求等}willReceiveProps(nextProps) {console.log('组件接收新 props', nextProps);}shouldUpdate(nextProps) {// 只有当特定属性变化时才更新return nextProps.value !== this.props.value;}willUpdate() {console.log('组件即将更新');}didUpdate() {console.log('组件已更新');}willUnmount() {console.log('组件即将卸载');// 在这里清理资源,如解绑事件、清除定时器等}didUnmount() {console.log('组件已卸载');}render() {const { props } = this;const { value } = props;return (<textstyle={{text: String(value),x: '50px',y: '50px',}}/>);}}
访问和利用上下文信息:
class ContextComponent extends Component {render() {const { context, props } = this;const { px2hd, theme, layout } = context;const { text } = props;// 使用 px2hd 转换单位const size = px2hd('24px');const { width, height } = layout;// 使用主题颜色const color = theme.color || '#000';return (<textstyle={{text,x: width / 2,y: height / 2,fill: color,fontSize: size,}}/>);}}
使用 forceUpdate 强制组件更新:
class ForceUpdateComponent extends Component {constructor(props, context) {super(props, context);this.state = {data: [],};}didMount() {// 模拟外部数据变化setTimeout(() => {this.state.data.push({ value: 1 });// 跳过 shouldUpdate 检查,强制更新this.forceUpdate();}, 1000);}render() {const { state } = this;const { data } = state;return (<textstyle={{text: `Data length: ${data.length}`,x: '50px',y: '50px',}}/>);}}
使用 setAnimate 控制组件动画:
class AnimatedComponent extends Component {didMount() {// 禁用动画this.setAnimate(false);}render() {const { props } = this;const { x, y } = props;return (<rectstyle={{x,y,width: '100px',height: '100px',fill: 'red',}}/>);}}
根据状态或属性进行条件渲染:
class ConditionalComponent extends Component {constructor(props, context) {super(props, context);this.state = {visible: true,};}didMount() {// 2秒后隐藏组件setTimeout(() => {this.setState({ visible: false });}, 2000);}render() {const { state, props } = this;const { visible } = state;const { text } = props;if (!visible) {return null;}return (<textstyle={{text,x: '50px',y: '50px',}}/>);}}
在图表中使用自定义组件:
import { Chart, Component, jsx } from '@antv/f2';// 自定义数据标签组件class DataLabel extends Component {render() {const { props, context } = this;const { data, xField, yField } = props;const { px2hd } = context;return (<group>{data.map((item) => {const x = px2hd(item[xField]);const y = px2hd(item[yField]);return (<textstyle={{text: String(item.value),x,y: y - 10,fill: '#000',fontSize: '12px',textAlign: 'center',}}/>);})}</group>);}}// 使用自定义组件const App = () => {const data = [{ genre: 'Action', value: 100 },{ genre: 'Comedy', value: 80 },];return (<Canvas pixelRatio={window.devicePixelRatio}><Chart data={data}><interval x="genre" y="value" /><DataLabel data={data} xField="genre" yField="value" /></Chart></Canvas>);};
Component 基类支持的属性:
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
zIndex | number | 0 | 组件的层级索引,用于控制渲染顺序,值越大越靠前 |
确保在 render 方法中使用 this.state 而不是 this.props。setState 是异步的,如果需要在状态更新后执行操作,可以使用回调函数:
this.setState({ count: 1 }, () => {console.log('状态已更新', this.state.count);});
检查 shouldUpdate 方法是否返回了 false。如果实现了 shouldUpdate,确保在需要更新时返回 true。
在 willUnmount 中清理所有副作用,包括:
willUnmount() {if (this.timer) {clearTimeout(this.timer);}if (this.handler) {window.removeEventListener('resize', this.handler);}}
由于 setState 是异步的,在回调或事件处理函数中访问状态时可能获取的不是最新值。可以使用函数式 setState:
this.setState((prevState) => ({count: prevState.count + 1,}));