我已将 Fabric 用于概念验证项目,总体思路与 D3 等相同。请记住,Fabric 对 DOM 元素进行操作,而 React 将数据呈现到 DOM 中,通常后者是延迟的。有两件事可以帮助您确保代码正常工作:
等到组件被挂载
为此,请将您的 Fabric 实例化放入 componentDidMount:
import React, { Component } from 'react';
import { fabric } from 'react-fabricjs';
import styles from './MyComponent.css';
class MyComponent extends Component {
componentWillMount() {
// dispatch some actions if you use Redux
}
componentDidMount() {
const canvas = new fabric.Canvas('c');
// do some stuff with it
}
render() {
return (
<div className={styles.myComponent}>
<canvas id="c" />
</div>
)
}
}
将 Fabric 构造函数放入 componentDidMount 可确保它不会失败,因为在执行此方法时,DOM 已准备就绪。 (但 props 有时不是,以防万一你使用 Redux)
使用 refs 计算实际的宽高
Refs 是对实际 DOM 元素的引用。你可以使用 refs 来做你可以使用 DOM API 来处理 DOM 元素的事情:选择子元素、查找父元素、分配样式属性、计算 innerHeight 和 innerWidth。后者正是您所需要的:
componentDidMount() {
const canvas = new fabric.Canvas('c', {
width: this.refs.canvas.clientWidth,
height: this.refs.canvas.clientHeight
});
// do some stuff with it
}
不要忘记定义this 的refs 属性。为此,您需要一个构造函数。整个事情看起来像
import React, { Component } from 'react';
import { fabric } from 'react-fabricjs';
import styles from './MyComponent.css';
class MyComponent extends Component {
constructor() {
super()
this.refs = {
canvas: {}
};
}
componentWillMount() {
// dispatch some actions if you use Redux
}
componentDidMount() {
const canvas = new fabric.Canvas('c', {
width: this.refs.canvas.clientWidth,
height: this.refs.canvas.clientHeight
});
// do some stuff with it
}
render() {
return (
<div className={styles.myComponent}>
<canvas
id="c"
ref={node => {
this.refs.canvas = node;
} />
</div>
)
}
}
将 Fabric 与组件状态或道具混合
您可以让您的 Fabric 实例对任何组件道具或状态更新做出反应。要使其工作,只需在componentDidUpdate 上更新您的 Fabric 实例(如您所见,您可以将其存储为组件自身属性的一部分)。仅仅依靠render 函数调用并没有真正的帮助,因为渲染的任何元素都不会随着新的道具或新的状态而改变。像这样的:
import React, { Component } from 'react';
import { fabric } from 'react-fabricjs';
import styles from './MyComponent.css';
class MyComponent extends Component {
constructor() {
this.refs = {
canvas: {}
};
}
componentWillMount() {
// dispatch some actions if you use Redux
}
componentDidMount() {
const canvas = new fabric.Canvas('c', {
width: this.refs.canvas.clientWidth,
height: this.refs.canvas.clientHeight
});
this.fabric = canvas;
// do some initial stuff with it
}
componentDidUpdate() {
const {
images = []
} = this.props;
const {
fabric
} = this;
// do some stuff as new props or state have been received aka component did update
images.map((image, index) => {
fabric.Image.fromURL(image.url, {
top: 0,
left: index * 100 // place a new image left to right, every 100px
});
});
}
render() {
return (
<div className={styles.myComponent}>
<canvas
id="c"
ref={node => {
this.refs.canvas = node;
} />
</div>
)
}
}
只需用您需要的代码替换图像渲染,这取决于新的组件状态或道具。不要忘记在画布上渲染新对象之前清理它!