带反应的动态JQuery菜单

问题描述:

我想用React(ES6)创建一个动态JQuery菜单。我遵循JQuery菜单示例(https://jqueryui.com/menu/),但其中的所有示例都创建静态菜单。它没有解释如何更改菜单项,如更新标签或启用。另外,我不想最终在React中实现新的菜单。带反应的动态JQuery菜单

我有我的菜单项,它假定嵌套级别的JSON数组。

let simple= [{ 
      disabled: true, 
      label: "Item1" 
     }, 
     { 
      label: "Item2" 
     }, 
     { 
      label: "-" 
     }, 
     { 
      label: "Item3" 
     }, 
     { 
      label: "Item4", 
      children: [ 
       { 
        label: "Sub Item1" 
       }, 
       { 
        label: "Sub Item2" 
       }, 
       { 
        label: "Sub Item3" 
       } 
      ] 
     }]; 

我想要更新标签或直接在菜单中完成任何json项目的显示。我需要避免手动DOM操作,因为这是一种容易出错的方法。

React中的动态操作对于突变功能来说很简单。首先,我想你已经这样做,你需要导入的JQuery库需要

import $ from 'jquery'; 
import 'jquery-ui/ui/core'; 
import 'jquery-ui/ui/widgets/menu'; 

而且你需要引用您的菜单的反应成分如下。动态生命周期将作为反应状态处理(https://facebook.github.io/react/docs/state-and-lifecycle.html)。我们使用一个状态,例如menuItems来管理JSON对象/数组。您可以看到该位置设置为绝对。没有这个,你的菜单将会导致你的整个文档展开,除非这是你想要的行为。

<ul ref="menu" style={{display: "none", position: "absolute"}}> 
    {this.state.menuItems.map(this.processMenuEntry.bind(this, 0))} 
</ul> 

processMenuEntry方法的实现如下。当然你可以更新这个方法来匹配任何不同的JSON结构。 我会建议使用className的一个小改动:“ui-state-disabled”而不是disabled:true。因此,您将有更多选项来自定义您的样式,而不仅仅是启用/禁用。下面的方法假定嵌套级别,以零开头,就像上面代码片段中的初始调用一样。确保为子组件分配密钥很重要。

processMenuEntry(level, entry, idx){ 
     let id= "menu"+ level+ "_"+ idx; 

     if(!entry.className){ 
      entry.className= ""; 
     } 

     let children= entry.children; 
     let child; 
     if(children && children.length){ 
      child= <li className= {entry.className} key= {id}><div>{entry.label}</div><ul>{children.map(this.processMenuEntry.bind(this, level+1))}</ul></li>; 
     }else{ 
      child= <li className= {entry.className} key= {id}><div>{entry.label}</div></li>; 
     } 

     return child; 
} 

确保在你的构造,使这个电话,所以你的方法将你的反应成分在HTML

this.processMenuEntry= this.processMenuEntry.bind(this); 

在componentDidMount添加此代码段相同的情况下,才能启动菜单API工作,除了你的点击处理程序。

componentDidMount(){ 
     $(this.refs.menu).menu({ 
      select: function(event, ui) { 
       //do 
      } 
     }); 
} 

现在,例如,如果要禁用菜单中的第二项,则可以简单地执行该操作。

simple[1].className= "ui-state-disabled"; 
this.setState({"menuItems": simple}); 

您可以和设定一个完全不同的JSON数组,并做出反应将它

this.setState({"menuItems": [{ 
    label: "Some new Item1" 
}]}); 

使用的护理“ - ”作为一个标签将一个分隔符添加到您的菜单JQuery菜单API的设计。

最后,在处理菜单切换或在外部点击时隐藏菜单,您可以查看下面的代码片段。当然,你可以根据你的工作进行修改。我在下面假设我们在点击锚点时切换菜单。检查用户在菜单外单击是否仅在菜单可见时才添加。

<a href="https://*.com" onClick={this.toggleMenu}>Test</a> 

componentWillUnmount(){ 
    this.stopMenuListeners(); 
} 

stopMenuListeners(){ 
    $(document).off("click.menuOutsideClicks"); 
} 

toggleMenu(event){ 
     let menu= $(this.refs.menu); 
     let visible= !menu.is(':visible'); 
     menu.slideToggle("fast"); 

     this.stopMenuListeners(); 
     if(visible){ 
      setTimeout(()=>{ 
       this._handler= $(document).on("click.menuOutsideClicks", (event)=>{ 
        if(!$(event.target).closest(menu).length){ 
         menu.slideUp('slow').hide(); 
         this.stopMenuListeners(); 
        } 
       }); 
      }); 
     } 

     event.stopPropagation(); 
     event.preventDefault(); 
}