当前位置:   article > 正文

Jsplumb的坑_react jsplumb 触摸屏无效

react jsplumb 触摸屏无效

一、前言

时隔三年,我跳去了某大厂工作了。从以前使用vue,到现在使用React,感觉还可以接受,毕竟现在好多框架都是开箱即用的。刚好有个拓扑图的需求,于是我技术选型了使用jsplumb,发现里面有不少坑,于是写下博客已作记录。

二、需要在container上加上position:relative;

如果你在使用jsplumb时,使用到它的api——setContainer的话,那么这个时候你就要注意了,一定要为这个container设置一个样式——position: relative;如下图1-1,图1-2:

                                                                                           图1-1

                                                                                              图1-2

至于为什么这样?其实我们可以打开控制台看到,jsplumb会为它自己画的元素加上position: absolute这个样式,如下图1-3

在这些元素的container上加上position: relative;它才不容易走样!!!这个样式问题可以解决90%的jsplumb的问题!请大家记住!!!

当然有些同学会问,为什么有时候窗口最大化最小化,或者resize窗口的时候,jsplumb不会自动跟踪dom的位置变化导致老是对不齐呢?这其实就是canvas的一个机制造成的。毕竟使用了canvas,你不得不通过监听window.resize来对canvas的高宽进行调整了。

像我下图,其实我用了一个偷懒的办法,直接把它设置成container设置成px像素,这样子就无论怎么缩小放大窗口,jsplumb绘制的元素都可以自动跟踪dom的位置变化了。

但是一旦把width,height设置成百分比,或者vw,vh,那么就要用window.resize方法了

 

二、如果你使用的是npm安装jsplumb而不是cdn引入的话

那么你就要像我这样子才能获取到真正的Jsplumb,才能用上它setContainer,deleteConnection等api

 

三、要使用jsplumb.ready

jsplumb和jquery一样,也是要等待元素加载完成才能使用的,不然它会因为找不到元素id而报错

所以我们要如下图那样,在componentDidMount加上:   

四、使用jsplumb.reset清除绘图缓存

如果你离开了当前的页面的时候,一定要记得使用jsplumb.reset()方法,把jsplumb的东西清除掉,不然他会一直保留在浏览器缓存,然后下次进去页面会出现很多意想不到的bug:

这个方法解决了好多坑呀,和上面说的position: relative;一样的。

 

五、完整代码

react代码:

  1. import React from 'react';
  2. import jsplumbData from '@/utils/jsplumb-data'; // 我的测试数据
  3. import Style from './index.css';
  4. import Jsplumb from 'jsplumb'; // 引入npm安装了的jsplumb
  5. // 这是一个坑,一定要这样才能获取到jsplumb,进而调用它的api接口
  6. const jsplumb = Jsplumb.jsPlumb;
  7. // 定义一个变量准备接受jsplumb创建的实例
  8. let instance = null;
  9. export default class JPChart extends React.Component {
  10. constructor(props) {
  11. super(props);
  12. this.state = {
  13. // 这是接收测试数据的节点数据
  14. nodes: [],
  15. // 这是接收测试数据的边的数据
  16. edges: []
  17. };
  18. }
  19. componentDidMount() {
  20. // 这是一些jsplumb绘图的配置
  21. const defaultSetting = {
  22. detachable: false, // 使用了这个属性,用鼠标拖动连线两端的端点就不会使得连线消失了
  23. endpoint: 'Blank', // 使得连线两端端点为空,我记得这里有四种值
  24. // 端点的样式
  25. endpointStyle: { fill: '#08B375', outlineStroke: '#08B375', outlineWidth: 2 },
  26. // 连线的方式,这里我选择了用直线连接
  27. connector: ['Straight'],
  28. // 这里确定连线是A元素的左端(Left)连到B元素的右端(Right)
  29. anchor: ['Left', 'Right'],
  30. // 允许打印日志,方便调试
  31. logEnabled: true,
  32. // 这个是连线的样式
  33. paintStyle: { stroke: 'lightgray', strokeWidth: 1 },
  34. // 这个是连线的箭头样式,不加这个,连线就不会有样式
  35. overlays: [ ['Arrow', { width: 12, length: 12, location: 1 }] ]
  36. };
  37. this.setState({
  38. nodes: jsplumbData.nodes,
  39. edges: jsplumbData.edges
  40. });
  41. // 这里是个坑,一定要加ready函数,不然图出不来
  42. jsplumb.ready(() => {
  43. // 这里我创建了一个实例
  44. // 很多人问直接使用jsplumb有什么不同,其实如果你要
  45. // 画多个拓扑图的话,那么你就要用getInstance创建多个实例
  46. // 我这里的需求只需要画一个,所以其实直接使用jsplumb
  47. // 不创建实例也可以,没什么区别的
  48. instance = jsplumb.getInstance();
  49. // 限定jsplumb绘制的元素只能在这个id为LZY的元素里面
  50. instance.setContainer("LZY");
  51. // 先清除一下画布,防止缓存,这里又是一个坑的解决方法
  52. instance.reset();
  53. // 遍历从而使得每个节点相连
  54. jsplumbData.edges.forEach(item => {
  55. instance.connect({
  56. ...defaultSetting,
  57. source: item.source,
  58. target: item.target
  59. });
  60. });
  61. // 遍历使得每个元素都可以进行拖拽
  62. jsplumbData.nodes.forEach(item => {
  63. instance.draggable(item.id);
  64. });
  65. });
  66. }
  67. // 在这里清除jsplumb缓存
  68. componentWillUnmount() {
  69. // 如果上面不是直接用jsplumb.getInstance创建实例的话
  70. // 就使用jsplumb.reset清除数据即可
  71. instance.reset();
  72. }
  73. render () {
  74. const nodes = this.state.nodes;
  75. return (
  76. <div className={ Style.root }>
  77. <div className={ Style.second }>
  78. { /* 这个LZY的div元素是jsplumb的绘画的地方 */ }
  79. <div className={ Style.LZY } id="LZY">
  80. {
  81. nodes.map(item => (
  82. <div id={ item.id } className={ Style.item } key={ item.id }>
  83. { item.label }
  84. {
  85. item.children.map(v => (
  86. <div className={ Style.child } key={ v.id }>{ v.label }</div>
  87. ))
  88. }
  89. </div>
  90. ))
  91. }
  92. </div>
  93. </div>
  94. <div className={ Style.first }>
  95. <div></div>
  96. </div>
  97. </div>
  98. );
  99. }
  100. }

css样式:

模拟数据:

  1. export default {
  2. nodes: [
  3. {
  4. id: 'l1',
  5. label: 1,
  6. children: [
  7. { id: 11, label: 11 },
  8. { id: 12, label: 12 },
  9. { id: 13, label: 13 }
  10. ]
  11. },
  12. {
  13. id: 'l2',
  14. label: 2,
  15. children: [
  16. { id: 21, label: 21 },
  17. { id: 22, label: 22 },
  18. { id: 23, label: 23 }
  19. ]
  20. },
  21. {
  22. id: 'l3',
  23. label: 3,
  24. children: [
  25. { id: 31, label: 31 },
  26. { id: 32, label: 32 },
  27. { id: 33, label: 33 }
  28. ]
  29. },
  30. {
  31. id: 'l4',
  32. label: 4,
  33. children: [
  34. { id: 41, label: 41 },
  35. { id: 42, label: 42 },
  36. { id: 43, label: 43 }
  37. ]
  38. }
  39. ],
  40. edges: [
  41. {
  42. source: 'l1',
  43. target: 'l2'
  44. },
  45. {
  46. source: 'l2',
  47. target: 'l3'
  48. },
  49. {
  50. source: 'l3',
  51. target: 'l4'
  52. }
  53. ]
  54. };

最后

jsplumb其实我还要研究更复杂的例子,并且将会对比g6,那么之后遇到什么坑,我会继续更新到这里,希望这对各位同学有所帮助吧,有兴趣的话可以点击一波关注~~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/117143
推荐阅读
相关标签
  

闽ICP备14008679号