Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pro-layout
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
packages
pro-layout
Commits
a7380c6b
Commit
a7380c6b
authored
Dec 16, 2020
by
Sendya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: route context
parent
dfab7a66
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
201 additions
and
99 deletions
+201
-99
demoBox.less
examples/demoBox.less
+14
-0
demoBox.tsx
examples/demoBox.tsx
+64
-0
index.tsx
examples/index.tsx
+15
-12
route-context.tsx
examples/route-context.tsx
+12
-11
side-menu.tsx
examples/side-menu.tsx
+68
-50
RouteContext.tsx
src/RouteContext.tsx
+8
-6
BaseMenu.tsx
src/SiderMenu/BaseMenu.tsx
+2
-5
SiderMenu.tsx
src/SiderMenu/SiderMenu.tsx
+2
-2
index.ts
src/hooks/context/index.ts
+16
-13
No files found.
examples/demoBox.less
0 → 100644
View file @
a7380c6b
.browser-nav {
padding: 2px 6px;
background-color: #ebedf1;
&::before {
content: '';
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #fd6458;
box-shadow: 20px 0 0 #ffbf2b, 40px 0 0 #24cc3d;
}
}
examples/demoBox.tsx
0 → 100644
View file @
a7380c6b
import
{
createApp
,
defineComponent
,
ref
,
h
,
onMounted
}
from
'vue'
;
import
{
RouterLink
}
from
'./mock-router'
;
import
*
as
Icon
from
'@ant-design/icons-vue'
;
import
'./demoBox.less'
;
export
const
DemoBox
=
defineComponent
({
setup
(
_
,
{
slots
})
{
const
instance
=
ref
();
const
frameRef
=
ref
();
const
content
=
():
void
=>
{
const
children
=
slots
?.
default
();
console
.
log
(
'frameRef.value'
,
frameRef
.
value
);
const
body
=
frameRef
.
value
.
contentDocument
.
body
;
const
head
=
frameRef
.
value
.
contentDocument
.
head
;
const
el
=
document
.
createElement
(
'div'
);
el
.
className
=
'demoBox'
body
.
appendChild
(
el
);
// const styleLink = document.createElement('link');
// styleLink.rel = 'stylesheet';
// styleLink.type = 'text/css';
// styleLink.href = './index.css';
head
.
innerHTML
=
`
<link href="/node_modules/normalize.css/normalize.css" type="text/css" rel="stylesheet">
<link href="./index.css" type="text/css" rel="stylesheet">
`
const
box
=
createApp
({
render
()
{
return
children
;
},
}).
use
(
RouterLink
);
const
filterIcons
=
[
'default'
,
'createFromIconfontCN'
,
'getTwoToneColor'
,
'setTwoToneColor'
];
Object
.
keys
(
Icon
)
.
filter
(
k
=>
!
filterIcons
.
includes
(
k
))
.
forEach
(
k
=>
{
box
.
component
(
Icon
[
k
].
displayName
,
Icon
[
k
]);
});
box
.
mount
(
el
);
instance
.
value
=
box
;
}
onMounted
(()
=>
{
content
();
})
return
{
frameRef
,
content
,
}
},
render
()
{
return
(
<
div
class=
"browser-mockup with-url"
>
<
div
class=
"browser-nav"
>
</
div
>
<
iframe
ref=
"frameRef"
height=
"450px"
width=
"100%"
style=
"border: 0;"
/>
</
div
>
)
}
});
examples/index.tsx
View file @
a7380c6b
import
'ant-design-vue/dist/antd.less'
;
import
{
createApp
,
defineComponent
,
watch
,
ref
}
from
'vue'
;
import
{
createApp
,
defineComponent
,
onMounted
,
watch
,
ref
,
reactive
}
from
'vue'
;
import
{
RouterLink
}
from
'./mock-router'
;
import
{
Button
,
Avatar
,
message
}
from
'ant-design-vue'
;
import
{
default
as
ProLayout
}
from
'../src/'
;
import
{
menus
}
from
'./menus'
;
import
*
as
Icon
from
'@ant-design/icons-vue'
;
import
{
createRouteContext
}
from
'../src/RouteContext'
;
import
{
createRouteContext
,
RouteContextProps
}
from
'../src/RouteContext'
;
import
{
DemoBox
}
from
'./demoBox'
;
const
BasicLayout
=
defineComponent
({
name
:
'BasicLayout'
,
inheritAttrs
:
false
,
setup
(
_
,
{
attrs
}
)
{
const
[
state
,
RouteContextProvider
]
=
createRouteContext
({
setup
()
{
const
state
=
reactive
<
RouteContextProps
>
({
collapsed
:
false
,
openKeys
:
[
'/dashboard'
,
'/form'
],
on
OpenKeys
:
(
keys
:
string
[])
=>
(
state
.
openKeys
=
keys
),
openKeys
:
[
'/dashboard'
],
set
OpenKeys
:
(
keys
:
string
[])
=>
(
state
.
openKeys
=
keys
),
selectedKeys
:
[
'/welcome'
],
on
SelectedKeys
:
(
keys
:
string
[])
=>
(
state
.
selectedKeys
=
keys
),
set
SelectedKeys
:
(
keys
:
string
[])
=>
(
state
.
selectedKeys
=
keys
),
isMobile
:
false
,
fixSiderbar
:
false
,
...
...
@@ -28,7 +29,8 @@ const BasicLayout = defineComponent({
hasHeader
:
true
,
hasFooterToolbar
:
false
,
setHasFooterToolbar
:
(
has
:
boolean
)
=>
(
state
.
hasFooterToolbar
=
has
),
});
})
const
[
RouteContextProvider
]
=
createRouteContext
();
const
cacheOpenKeys
=
ref
<
string
[]
>
([]);
watch
(
...
...
@@ -44,9 +46,8 @@ const BasicLayout = defineComponent({
);
return
()
=>
(
<
RouteContextProvider
>
<
RouteContextProvider
value=
{
state
}
>
<
ProLayout
{
...
attrs
}
v
-
model=
{
[
state
.
collapsed
,
'collapsed'
]
}
title=
{
'Pro Layout'
}
layout=
{
'side'
}
...
...
@@ -57,7 +58,7 @@ const BasicLayout = defineComponent({
fixedHeader=
{
state
.
fixedHeader
}
contentWidth=
{
'Fixed'
}
primaryColor=
{
'#1890ff'
}
contentStyle=
{
{
minHeight
:
'
5
00px'
}
}
contentStyle=
{
{
minHeight
:
'
2
00px'
}
}
siderWidth=
{
state
.
sideWidth
}
v
-
slots=
{
{
rightContentRender
:
()
=>
(
...
...
@@ -91,7 +92,9 @@ const SimpleDemo = {
return
()
=>
(
<
div
class=
"components"
>
<
h2
>
# BasicLayout
</
h2
>
<
BasicLayout
/>
<
DemoBox
>
<
BasicLayout
/>
</
DemoBox
>
</
div
>
);
},
...
...
examples/route-context.tsx
View file @
a7380c6b
import
{
createApp
,
defineComponent
,
ref
,
reactive
,
toRaw
,
onMounted
}
from
'vue'
;
import
{
Card
,
Space
,
Button
}
from
'ant-design-vue'
;
import
{
createRouteContext
,
useRouteContext
}
from
'../src/RouteContext'
;
import
{
createRouteContext
,
useRouteContext
,
RouteContextProps
}
from
'../src/RouteContext'
;
import
'ant-design-vue/dist/antd.less'
;
...
...
@@ -9,14 +9,15 @@ const DemoComponent = {
const
state
=
reactive
({
name
:
'value'
,
});
const
[
routeContext
,
RouteContextProvider
]
=
createRouteContext
({
hasSideMenu
:
true
,
collapsed
:
true
,
isMobile
:
false
,
menuData
:
[]
const
context
=
reactive
<
RouteContextProps
>
({
menuData
:
[],
selectedKeys
:
[],
openKeys
:
[],
collapsed
:
false
,
});
const
[
RouteContextProvider
]
=
createRouteContext
();
return
()
=>
(
<
div
class=
"components"
>
<
h2
>
# Template
</
h2
>
...
...
@@ -26,8 +27,8 @@ const DemoComponent = {
type=
"primary"
onClick=
{
()
=>
{
state
.
name
=
new
Date
().
getTime
().
toString
()
routeContext
.
collapsed
=
!
routeC
ontext
.
collapsed
routeC
ontext
.
menuData
=
[
context
.
collapsed
=
!
c
ontext
.
collapsed
c
ontext
.
menuData
=
[
{
path
:
`/dashboard/${state.name}`
,
name
:
`${state.name}`
,
...
...
@@ -42,11 +43,11 @@ const DemoComponent = {
<
div
style=
{
{
margin
:
'12px 0'
}
}
>
<
p
>
state.name:
{
JSON
.
stringify
(
state
.
name
)
}
</
p
>
routeContext:
<
pre
>
{
JSON
.
stringify
(
routeC
ontext
,
null
,
4
)
}
</
pre
>
<
pre
>
{
JSON
.
stringify
(
c
ontext
,
null
,
4
)
}
</
pre
>
</
div
>
</
Card
>
<
div
class=
"demo"
style=
"background: rgb(244,244,244);"
>
<
RouteContextProvider
>
<
RouteContextProvider
value=
{
context
}
>
<
TestChildComponent
/>
</
RouteContextProvider
>
</
div
>
...
...
examples/side-menu.tsx
View file @
a7380c6b
...
...
@@ -4,76 +4,94 @@ import 'ant-design-vue/dist/antd.less';
import
'./side-menu.less'
;
import
{
Layout
,
Input
,
Space
,
Switch
,
message
}
from
'ant-design-vue'
;
import
{
menus
}
from
'./menus'
;
import
{
RouterLink
}
from
'./mock-router'
;
import
{
default
as
SiderMenuWrapper
}
from
'../src/SiderMenu'
;
import
{
useMenu
}
from
'../src/hooks/useMenu
'
;
import
{
createRouteContext
,
RouteContextProps
}
from
'../src/RouteContext
'
;
import
*
as
Icon
from
'@ant-design/icons-vue'
;
import
{
MenuTheme
}
from
'../src/typings'
;
const
DemoComponent
=
{
setup
()
{
const
[
menuState
]
=
useMenu
({
const
state
=
reactive
<
RouteContextProps
>
({
collapsed
:
false
,
openKeys
:
[
''
],
openKeys
:
[
'/dashboard'
,
'/form'
],
setOpenKeys
:
(
keys
:
string
[])
=>
(
state
.
openKeys
=
keys
),
selectedKeys
:
[
'/welcome'
],
});
const
state
=
reactive
({
setSelectedKeys
:
(
keys
:
string
[])
=>
(
state
.
selectedKeys
=
keys
),
isMobile
:
false
,
fixSiderbar
:
false
,
fixedHeader
:
false
,
menuData
:
[...
menus
],
sideWidth
:
208
,
hasSideMenu
:
true
,
hasHeader
:
true
,
hasFooterToolbar
:
false
,
setHasFooterToolbar
:
(
has
:
boolean
)
=>
(
state
.
hasFooterToolbar
=
has
),
})
const
[
RouteContextProvider
]
=
createRouteContext
();
const
myState
=
reactive
({
theme
:
'light'
,
});
const
handleCollapse
=
(
collapsed
:
boolean
)
=>
{
menuS
tate
.
collapsed
=
collapsed
;
s
tate
.
collapsed
=
collapsed
;
}
return
()
=>
(
<
div
class=
"components"
>
<
h2
>
# SideMenu
</
h2
>
<
div
>
<
div
style=
"margin: 16px;"
>
<
Space
>
<
Switch
checked
-
children=
"dark"
un
-
checked
-
children=
"light"
checked=
{
state
.
theme
===
'dark'
}
onChange=
{
()
=>
{
(
state
.
theme
=
s
tate
.
theme
===
'dark'
?
'light'
:
'dark'
)}
}
/>
<
Switch
checked
-
children=
"dark"
un
-
checked
-
children=
"light"
checked=
{
state
.
theme
===
'dark'
}
onChange=
{
()
=>
{
(
myState
.
theme
=
myS
tate
.
theme
===
'dark'
?
'light'
:
'dark'
)}
}
/>
</
Space
>
</
div
>
<
div
class=
"demo"
style=
"background: rgb(244,244,244); min-height: 400px;"
>
<
div
class=
"container side-menu-demo"
>
<
Layout
class=
"ant-pro-basicLayout"
>
<
SiderMenuWrapper
title=
{
'Pro Layout'
}
layout=
{
'side'
}
theme=
{
state
.
theme
as
MenuTheme
}
isMobile=
{
false
}
collapsed=
{
menuState
.
collapsed
}
menuData=
{
menus
}
// openKeys={menuState.openKeys}
// selectedKeys={menuState.selectedKeys}
onCollapse=
{
handleCollapse
}
matchMenuKeys=
{
[]
}
contentWidth=
{
'Fixed'
}
primaryColor=
{
'#1890ff'
}
siderWidth=
{
208
}
menuExtraRender=
{
(
props
)
=>
!
props
.
collapsed
?
(
<
div
>
<
Input
.
Search
placeholder=
"Search.."
style=
{
{
width
:
'100%'
}
}
onSearch=
{
(
value
:
string
)
=>
{
message
.
info
(
`Search click: ${value}`
)
}
}
/>
</
div
>
)
:
null
}
// menuFooterRender={(props) => props.collapsed ? undefined : (
// <div style="color: #fff; padding: 8px 16px; overflow: hidden;">
// <span>自定义页脚</span>
// </div>
// )}
/>
<
Layout
>
<
Layout
.
Header
style=
"background: #fff; padding: 0; height: 48px; line-height: 48px;"
></
Layout
.
Header
>
<
Layout
.
Content
style=
{
{
margin
:
'24px 16px'
,
padding
:
'24px'
,
background
:
'#fff'
,
minHeight
:
'280px'
,
}
}
>
<
div
>
Context
</
div
>
</
Layout
.
Content
>
<
RouteContextProvider
value=
{
state
}
>
<
Layout
class=
"ant-pro-basicLayout"
>
<
SiderMenuWrapper
title=
{
'Pro Layout'
}
layout=
{
'side'
}
navTheme=
{
myState
.
theme
as
MenuTheme
}
isMobile=
{
false
}
collapsed=
{
state
.
collapsed
}
// openKeys={menuState.openKeys}
// selectedKeys={menuState.selectedKeys}
onCollapse=
{
handleCollapse
}
matchMenuKeys=
{
[]
}
contentWidth=
{
'Fixed'
}
primaryColor=
{
'#1890ff'
}
siderWidth=
{
208
}
menuExtraRender=
{
(
props
)
=>
!
props
.
collapsed
?
(
<
div
>
<
Input
.
Search
placeholder=
"Search.."
style=
{
{
width
:
'100%'
}
}
onSearch=
{
(
value
:
string
)
=>
{
message
.
info
(
`Search click: ${value}`
)
}
}
/>
</
div
>
)
:
null
}
// menuFooterRender={(props) => props.collapsed ? undefined : (
// <div style="color: #fff; padding: 8px 16px; overflow: hidden;">
// <span>自定义页脚</span>
// </div>
// )}
/>
<
Layout
>
<
Layout
.
Header
style=
"background: #fff; padding: 0; height: 48px; line-height: 48px;"
></
Layout
.
Header
>
<
Layout
.
Content
style=
{
{
margin
:
'24px 16px'
,
padding
:
'24px'
,
background
:
'#fff'
,
minHeight
:
'280px'
,
}
}
>
<
div
>
Context
</
div
>
</
Layout
.
Content
>
</
Layout
>
</
Layout
>
</
Layout
>
</
RouteContextProvider
>
</
div
>
</
div
>
</
div
>
...
...
@@ -90,4 +108,4 @@ Object.keys(Icon)
app
.
component
(
Icon
[
k
].
displayName
,
Icon
[
k
]);
});
app
.
mount
(
'#__vue-content>div'
);
app
.
use
(
RouterLink
).
mount
(
'#__vue-content>div'
);
src/RouteContext.tsx
View file @
a7380c6b
...
...
@@ -2,11 +2,13 @@ import { InjectionKey, VNodeChild } from 'vue';
import
{
createContext
,
useContext
}
from
'./hooks/context'
;
import
{
MenuDataItem
}
from
'./typings'
;
import
{
PureSettings
}
from
'./defaultSettings'
;
export
interface
Route
{
path
:
string
;
breadcrumbName
:
string
;
children
?:
Omit
<
Route
,
'children'
>
[];
}
export
interface
BreadcrumbProps
{
prefixCls
?:
string
;
routes
?:
Route
[];
...
...
@@ -18,10 +20,10 @@ export interface BreadcrumbProps {
export
type
BreadcrumbListReturn
=
Pick
<
BreadcrumbProps
,
Extract
<
keyof
BreadcrumbProps
,
'routes'
|
'itemRender'
>>
;
export
interface
MenuState
{
selectedKeys
?
:
string
[];
openKeys
?
:
string
[];
onSelectedKeys
:
(
key
:
string
[])
=>
void
;
onOpenKeys
:
(
key
:
string
[])
=>
void
;
selectedKeys
:
string
[];
openKeys
:
string
[];
setSelectedKeys
?
:
(
key
:
string
[])
=>
void
;
setOpenKeys
?
:
(
key
:
string
[])
=>
void
;
}
export
interface
RouteContextProps
extends
Partial
<
PureSettings
>
,
MenuState
{
...
...
@@ -42,8 +44,8 @@ export interface RouteContextProps extends Partial<PureSettings>, MenuState {
const
routeContextInjectKey
:
InjectionKey
<
RouteContextProps
>
=
Symbol
();
export
const
createRouteContext
=
(
context
:
RouteContextProps
)
=>
createContext
<
RouteContextProps
>
(
context
,
routeContextInjectKey
);
export
const
createRouteContext
=
()
=>
createContext
<
RouteContextProps
>
(
routeContextInjectKey
);
export
const
useRouteContext
=
()
=>
useContext
<
RouteContextProps
>
(
routeContextInjectKey
);
src/SiderMenu/BaseMenu.tsx
View file @
a7380c6b
...
...
@@ -167,10 +167,8 @@ export default defineComponent({
emits
:
[
'update:openKeys'
,
'update:selectedKeys'
],
setup
(
props
,
{
emit
})
{
const
{
mode
,
i18n
}
=
toRefs
(
props
);
const
state
=
useMenuState
();
const
isInline
=
computed
(()
=>
mode
.
value
===
'inline'
);
const
handleOpenChange
:
OpenEventHandler
=
(
openKeys
:
string
[]):
void
=>
{
state
?.
setOpenKeys
(
openKeys
);
emit
(
'update:openKeys'
,
openKeys
);
};
const
handleSelect
=
(
params
:
{
...
...
@@ -180,7 +178,6 @@ export default defineComponent({
domEvent
:
MouseEvent
;
selectedKeys
:
string
[];
}):
void
=>
{
state
?.
setSelectedKeys
(
params
.
selectedKeys
);
emit
(
'update:selectedKeys'
,
params
.
selectedKeys
);
};
return
()
=>
(
...
...
@@ -190,8 +187,8 @@ export default defineComponent({
inlineIndent=
{
16
}
mode=
{
props
.
mode
}
theme=
{
props
.
theme
as
'dark'
|
'light'
}
openKeys=
{
props
.
openKeys
||
state
?.
openKeys
.
value
||
[]
}
selectedKeys=
{
props
.
selectedKeys
||
state
?.
selectedKeys
.
value
||
[]
}
openKeys=
{
props
.
openKeys
||
[]
}
selectedKeys=
{
props
.
selectedKeys
||
[]
}
onOpenChange=
{
handleOpenChange
}
onSelect=
{
handleSelect
}
>
...
...
src/SiderMenu/SiderMenu.tsx
View file @
a7380c6b
...
...
@@ -133,10 +133,10 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
class=
{
`${baseClassName}-menu`
}
{
...
{
'
onUpdate
:
openKeys
':
(
$event
:
string
[])
=
>
{
context
.
on
OpenKeys
(
$event
);
context
?.
set
OpenKeys
(
$event
);
}
,
'onUpdate:selectedKeys': ($event: string[]) =
>
{
context
.
on
SelectedKeys
(
$event
);
context
?.
set
SelectedKeys
(
$event
);
}
,
}}
/
>
...
...
src/hooks/context/index.ts
View file @
a7380c6b
...
...
@@ -3,47 +3,50 @@ import {
InjectionKey
,
provide
,
inject
,
reactive
,
readonly
,
SetupContext
,
UnwrapRef
,
VNode
,
PropType
,
DefineComponent
,
toRaw
,
}
from
'vue'
;
export
type
ContextType
<
T
>
=
any
;
export
type
CreateContext
<
T
>
=
[
UnwrapRef
<
T
>
|
T
,
//
UnwrapRef<T> | T,
DefineComponent
<
{},
()
=>
VNode
|
VNode
[]
|
undefined
,
any
>
,
];
export
const
createContext
=
<
T
>
(
context
:
ContextType
<
T
>
,
//
context: ContextType<T>,
contextInjectKey
:
InjectionKey
<
ContextType
<
T
>>
=
Symbol
(),
):
CreateContext
<
T
>
=>
{
const
state
=
reactive
<
ContextType
<
T
>>
({
...
toRaw
(
context
),
});
//
const state = reactive<ContextType<T>>({
//
...toRaw(context),
//
});
const
ContextProvider
=
defineComponent
({
name
:
'ContextProvider'
,
inheritAttrs
:
false
,
setup
(
props
,
{
slots
}:
SetupContext
)
{
provide
(
contextInjectKey
,
readonly
(
state
));
props
:
{
value
:
{
type
:
Object
as
PropType
<
ContextType
<
T
>>
,
required
:
true
,
},
},
setup
(
props
:
{
value
:
ContextType
<
T
>
},
{
slots
}:
SetupContext
)
{
provide
(
contextInjectKey
,
readonly
(
props
.
value
));
return
()
=>
slots
.
default
?.();
},
});
return
[
state
,
ContextProvider
];
return
[
ContextProvider
];
};
export
const
useContext
=
<
T
>
(
contextInjectKey
:
InjectionKey
<
ContextType
<
T
>>
=
Symbol
(),
defaultValue
?:
ContextType
<
T
>
,
):
T
=>
{
return
readonly
(
inject
(
contextInjectKey
,
defaultValue
||
({}
as
T
)
));
return
inject
(
contextInjectKey
,
defaultValue
||
({}
as
T
));
};
// :: examples ::
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment