我有一个通过Fabric.js使用重度HTML5画布的应用程序。该应用程序是基于Angular 1.x编写的,我计划将其移植到React。我的应用程序允许编写文本和绘制线条、矩形和椭圆。还可以移动、放大、收缩、选择、剪切、复制和粘贴一个或多个这样的对象。还可以使用各种快捷键缩放和平移画布。简而言之,我的应用程序充分利用了Fabric.js。
我找不到太多关于如何将Fabric.js与React一起使用的信息,所以我担心的是: 1.是否可以不进行重大修改;2.它是否有意义,或者我是否应该使用其他对React有更好支持的扩展canvas库?
我能找到的唯一的React+Fabric.js例子是react-komik,但是它比我的应用程序简单得多。我主要关注的是Fabric.js的事件处理和DOM操作,以及它们对React的影响。
似乎还有一个用于React的画布库,称为react-canvas,但与Fabric.js相比,它似乎缺少很多功能。
我必须考虑什么(关于DOM操作、事件处理等)在React应用程序中使用Fabric.js时?
发布于 2016-08-26 01:32:54
我们在我们的应用程序中遇到了同样的问题,即如何在react中使用Fabric.js。我的建议是将fabric视为一个不受控制的组件。拥有fabric实例,你的整个应用程序都可以与之对话并进行fabric调用,然后当有任何变化时,使用.toObject() call将整个fabric状态放入您的Redux存储中。然后,您的React应用程序可以从全局Redux状态读取fabric状态,就像您在任何常规React应用程序中所做的那样。
我在StackOverflow代码编辑器中找不到可以工作的示例,但是here is a JSFiddle example实现了我推荐的模式。
发布于 2016-08-28 06:55:50
我在一个概念验证项目中使用了Fabric,其总体思路与D3相同。请记住,Fabric在DOM元素上操作,而React将数据呈现到DOM中,而后者通常是延迟的。有两件事可以帮助你确保你的代码正常工作:
等待组件挂载完成
为此,请将结构实例化放入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已经准备好了。(但道具有时不是,如果你使用Redux,只是以防万一)
使用refs计算实际的宽度和高度
Refs是对实际DOM元素的引用。通过使用DOM,您可以对refs执行与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>
)
}
}只需将图像渲染替换为所需的代码,这取决于新的组件状态或属性。在渲染新对象之前,也不要忘记清理画布!
发布于 2019-11-17 02:48:18
使用react 16.8或更新版本,您还可以创建自定义钩子:
import React, { useRef, useCallback } from 'react';
const useFabric = (onChange) => {
const fabricRef = useRef();
const disposeRef = useRef();
return useCallback((node) => {
if (node) {
fabricRef.current = new fabric.Canvas(node);
if (onChange) {
disposeRef.current = onChange(fabricRef.current);
}
}
else if (fabricRef.current) {
fabricRef.current.dispose();
if (disposeRef.current) {
disposeRef.current();
disposeRef.current = undefined;
}
}
}, []);
};用法
const FabricDemo = () => {
const ref = useFabric((fabricCanvas) => {
console.log(fabricCanvas)
});
return <div style={{border: '1px solid red'}}>
<canvas ref={ref} width={300} height={200} />
</div>
}https://stackoverflow.com/questions/37565041
复制相似问题