@@ -3,11 +3,17 @@ import { connect } from "react-redux";
33import { withRouter } from "react-router-dom" ;
44import { Scrollbars } from "react-custom-scrollbars" ;
55import { Tag } from "antd" ;
6- import { deleteTaglist } from "@/store/actions" ;
7-
6+ import { deleteTag , emptyTaglist , closeOtherTags } from "@/store/actions" ;
87class TagList extends Component {
8+ tagListContainer = React . createRef ( ) ;
9+ contextMenuContainer = React . createRef ( ) ;
10+ state = {
11+ left : 0 ,
12+ top : 0 ,
13+ menuVisible : false ,
14+ } ;
915 handleClose = ( tag ) => {
10- const { history, deleteTaglist , taglist } = this . props ;
16+ const { history, deleteTag , taglist } = this . props ;
1117 const path = tag . path ;
1218 const currentPath = history . location . pathname ;
1319 const length = taglist . length ;
@@ -29,41 +35,128 @@ class TagList extends Component {
2935 }
3036
3137 // 先跳转路由,再修改state树的taglist
32- deleteTaglist ( tag ) ;
38+ deleteTag ( tag ) ;
3339 } ;
3440 handleClick = ( path ) => {
3541 this . props . history . push ( path ) ;
3642 } ;
43+ openContextMenu = ( tag , event ) => {
44+ event . preventDefault ( ) ;
45+ const menuMinWidth = 105 ;
46+ const clickX = event . clientX ;
47+ const clickY = event . clientY ; //事件发生时鼠标的Y坐标
48+ const clientWidth = this . tagListContainer . current . clientWidth ; // container width
49+ const maxLeft = clientWidth - menuMinWidth ; // left boundary
50+
51+ // 当鼠标点击位置大于左侧边界时,说明鼠标点击的位置偏右,将菜单放在左边
52+ if ( clickX > maxLeft ) {
53+ this . setState ( {
54+ left : clickX - menuMinWidth + 15 ,
55+ top : clickY ,
56+ menuVisible : true ,
57+ currentTag : tag ,
58+ } ) ;
59+ } else {
60+ // 反之,当鼠标点击的位置偏左,将菜单放在右边
61+ this . setState ( {
62+ left : clickX ,
63+ top : clickY ,
64+ menuVisible : true ,
65+ currentTag : tag ,
66+ } ) ;
67+ }
68+ } ;
69+ handleClickOutside = ( event ) => {
70+ const { menuVisible } = this . state ;
71+ const isOutside = ! (
72+ this . contextMenuContainer . current &&
73+ this . contextMenuContainer . current . contains ( event . target )
74+ ) ;
75+ if ( isOutside && menuVisible ) {
76+ this . closeContextMenu ( ) ;
77+ }
78+ } ;
79+ closeContextMenu ( ) {
80+ this . setState ( {
81+ menuVisible : false ,
82+ } ) ;
83+ }
84+ componentDidMount ( ) {
85+ document . body . addEventListener ( "click" , this . handleClickOutside ) ;
86+ }
87+ componentWillUnmount ( ) {
88+ document . body . removeEventListener ( "click" , this . handleClickOutside ) ;
89+ }
90+ handleCloseAllTags = ( ) => {
91+ this . props . emptyTaglist ( ) ;
92+ this . props . history . push ( "/dashboard" ) ;
93+ this . closeContextMenu ( ) ;
94+ } ;
95+ handleRefreshTag = ( ) => {
96+ const { path } = this . state . currentTag ;
97+ this . props . history . push ( path ) ;
98+ this . closeContextMenu ( ) ;
99+ } ;
100+ handleCloseOtherTags = ( ) => {
101+ const currentTag = this . state . currentTag ;
102+ const { path } = currentTag ;
103+ this . props . closeOtherTags ( currentTag )
104+ this . props . history . push ( path ) ;
105+ this . closeContextMenu ( ) ;
106+ } ;
37107 render ( ) {
108+ const { left, top, menuVisible } = this . state ;
38109 const { taglist, history } = this . props ;
39110 const currentPath = history . location . pathname ;
40111 return (
41- < Scrollbars
42- autoHide
43- autoHideTimeout = { 1000 }
44- autoHideDuration = { 200 }
45- hideTracksWhenNotNeeded = { true }
46- renderView = { props => < div { ...props } className = "scrollbar-container" /> }
47- renderTrackVertical = { props => < div { ...props } className = "scrollbar-track-vertical" /> }
48- >
49- < ul className = "tags-wrap" >
50- { taglist . map ( ( tag ) => (
51- < li key = { tag . path } >
52- < Tag
53- onClose = { this . handleClose . bind ( null , tag ) }
54- closable = { tag . path !== "/dashboard" }
55- color = { currentPath === tag . path ? "geekblue" : "gold" }
56- onClick = { this . handleClick . bind ( null , tag . path ) }
57- >
58- { tag . title }
59- </ Tag >
60- </ li >
61- ) ) }
62- </ ul >
63- </ Scrollbars >
112+ < >
113+ < Scrollbars
114+ autoHide
115+ autoHideTimeout = { 1000 }
116+ autoHideDuration = { 200 }
117+ hideTracksWhenNotNeeded = { true }
118+ renderView = { ( props ) => (
119+ < div { ...props } className = "scrollbar-container" />
120+ ) }
121+ renderTrackVertical = { ( props ) => (
122+ < div { ...props } className = "scrollbar-track-vertical" />
123+ ) }
124+ >
125+ < ul className = "tags-wrap" ref = { this . tagListContainer } >
126+ { taglist . map ( ( tag ) => (
127+ < li key = { tag . path } >
128+ < Tag
129+ onClose = { this . handleClose . bind ( null , tag ) }
130+ closable = { tag . path !== "/dashboard" }
131+ color = { currentPath === tag . path ? "geekblue" : "gold" }
132+ onClick = { this . handleClick . bind ( null , tag . path ) }
133+ onContextMenu = { this . openContextMenu . bind ( null , tag ) }
134+ >
135+ { tag . title }
136+ </ Tag >
137+ </ li >
138+ ) ) }
139+ </ ul >
140+ </ Scrollbars >
141+ { menuVisible ? (
142+ < ul
143+ className = "contextmenu"
144+ style = { { left : `${ left } px` , top : `${ top } px` } }
145+ ref = { this . contextMenuContainer }
146+ >
147+ < li onClick = { this . handleRefreshTag } > 刷新</ li >
148+ < li onClick = { this . handleCloseOtherTags } > 关闭其他</ li >
149+ < li onClick = { this . handleCloseAllTags } > 关闭所有</ li >
150+ </ ul >
151+ ) : null }
152+ </ >
64153 ) ;
65154 }
66155}
67156export default withRouter (
68- connect ( ( state ) => state . tagsView , { deleteTaglist } ) ( TagList )
157+ connect ( ( state ) => state . tagsView , {
158+ deleteTag,
159+ emptyTaglist,
160+ closeOtherTags,
161+ } ) ( TagList )
69162) ;
0 commit comments