mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: AnchorNav组件支持树形结构 (#8969)
Co-authored-by: yanglu19 <yanglu19@baidu.com>
This commit is contained in:
parent
d9ace501e3
commit
d9fb3ddb75
@ -12,6 +12,8 @@ order: 68
|
||||
|
||||
## 基本用法
|
||||
|
||||
`6.1.0`及以上版本垂直方向支持配置子节点
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "anchor-nav",
|
||||
@ -39,6 +41,24 @@ order: 68
|
||||
},
|
||||
{
|
||||
"title": "工作信息",
|
||||
"children": [
|
||||
{
|
||||
"title": "工作信息-1",
|
||||
"type": "form",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "workInfo1-1",
|
||||
"label": "工作信息1-1:"
|
||||
},
|
||||
{
|
||||
"name": "workInfo1-2",
|
||||
"type": "input-text",
|
||||
"label": "工作信息1-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
@ -60,6 +80,29 @@ order: 68
|
||||
},
|
||||
{
|
||||
"title": "兴趣爱好",
|
||||
"children": [
|
||||
{
|
||||
"title": "兴趣爱好1-1",
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
"title": "兴趣爱好1-1",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "interest1-1",
|
||||
"label": "interest1-1"
|
||||
},
|
||||
{
|
||||
"name": "interest1-2",
|
||||
"type": "input-text",
|
||||
"label": "interest1-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
@ -235,6 +278,25 @@ order: 68
|
||||
{
|
||||
"title": "工作信息",
|
||||
"href": "work",
|
||||
"children": [
|
||||
{
|
||||
"title": "工作信息-1",
|
||||
"href": "work-1",
|
||||
"type": "form",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "workInfo1-1",
|
||||
"label": "工作信息1-1:"
|
||||
},
|
||||
{
|
||||
"name": "workInfo1-2",
|
||||
"type": "input-text",
|
||||
"label": "工作信息1-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
@ -332,6 +394,24 @@ order: 68
|
||||
},
|
||||
{
|
||||
"title": "工作信息",
|
||||
"children": [
|
||||
{
|
||||
"title": "工作信息-1",
|
||||
"type": "form",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "workInfo1-1",
|
||||
"label": "工作信息1-1:"
|
||||
},
|
||||
{
|
||||
"name": "workInfo1-2",
|
||||
"type": "input-text",
|
||||
"label": "工作信息1-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
@ -409,5 +489,5 @@ order: 68
|
||||
| active | `string` | | 需要定位的区域 |
|
||||
| links[x].title | `string` | | 区域 标题 |
|
||||
| links[x].href | `string` | | 区域 标识 |
|
||||
| links[x].body | [SchemaNode](../types/schemanode) | | 区域 内容区 |
|
||||
| links[x].body | [SchemaNode](../types/schemanode) | | 区域 内容区,`6.1.0`及以上版本垂直方向支持配置子节点 |
|
||||
| links[x].className | `string` | `"bg-white b-l b-r b-b wrapper-md"` | 区域成员 样式 |
|
||||
|
@ -13,6 +13,9 @@
|
||||
> .#{$ns}AnchorNav-link {
|
||||
position: relative;
|
||||
display: block;
|
||||
&.#{$ns}AnchorNav-link-child {
|
||||
margin-left: px2rem(16px);
|
||||
}
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
|
@ -84,7 +84,6 @@ export class AnchorNav extends React.Component<AnchorNavProps, AnchorNavState> {
|
||||
|
||||
const sectionRootDom =
|
||||
this.contentDom && (this.contentDom.current as HTMLElement);
|
||||
|
||||
this.updateSectionOffset(sectionRootDom, false);
|
||||
this.observer = new MutationObserver(() =>
|
||||
// TODO: 牺牲性能
|
||||
@ -185,7 +184,6 @@ export class AnchorNav extends React.Component<AnchorNavProps, AnchorNavState> {
|
||||
this.setState({fromSelect: true});
|
||||
// 滚动到对应段落
|
||||
this.scrollToSection(key);
|
||||
|
||||
const sectionRootDom =
|
||||
this.contentDom && (this.contentDom.current as HTMLElement);
|
||||
|
||||
@ -215,11 +213,17 @@ export class AnchorNav extends React.Component<AnchorNavProps, AnchorNavState> {
|
||||
const {classnames: cx, active: activeProp} = this.props;
|
||||
const {title, name} = link.props;
|
||||
const active = activeProp === undefined && index === 0 ? name : activeProp;
|
||||
// 判断是否为子节点,子节点key为 <父节点索引>-<子节点索引>
|
||||
const isChild = link.key?.split('-').length >= 2;
|
||||
|
||||
return (
|
||||
<li
|
||||
className={cx('AnchorNav-link', active === name ? 'is-active' : '')}
|
||||
key={index}
|
||||
className={cx(
|
||||
'AnchorNav-link',
|
||||
isChild ? 'AnchorNav-link-child' : '',
|
||||
String(active) === String(name) ? 'is-active' : ''
|
||||
)}
|
||||
key={link.key}
|
||||
onClick={() => this.handleSelect(name)}
|
||||
>
|
||||
<a title={title}>{title}</a>
|
||||
@ -234,11 +238,11 @@ export class AnchorNav extends React.Component<AnchorNavProps, AnchorNavState> {
|
||||
|
||||
const {active: activeProp, classnames} = this.props;
|
||||
const name = section.props.name;
|
||||
const key = section.key;
|
||||
const active = activeProp === undefined && index === 0 ? name : activeProp;
|
||||
|
||||
return React.cloneElement(section, {
|
||||
...section.props,
|
||||
key: index,
|
||||
key,
|
||||
classnames,
|
||||
active
|
||||
});
|
||||
|
@ -206,3 +206,120 @@ test('Renderer:anchorNav with active', async () => {
|
||||
container.querySelector('.two .cxd-AnchorNav-link.is-active')
|
||||
).toHaveTextContent('工作信息');
|
||||
});
|
||||
|
||||
// 4. 子菜单
|
||||
test('Renderer:anchorNav with children', async () => {
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
body: {
|
||||
type: 'anchor-nav',
|
||||
direction: 'horizontal',
|
||||
links: [
|
||||
{
|
||||
title: '基本信息',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
title: '基本信息',
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'name',
|
||||
label: '姓名:'
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
type: 'input-email',
|
||||
label: '邮箱:'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
children: [
|
||||
{
|
||||
title: '基本信息1-1',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
title: '基本信息1-1',
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'cname1',
|
||||
label: 'cname1'
|
||||
},
|
||||
{
|
||||
name: 'caddress1',
|
||||
type: 'input-text',
|
||||
label: 'caddress1'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '基本信息1-2',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
title: '基本信息1-2',
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'cname2',
|
||||
label: 'cname2'
|
||||
},
|
||||
{
|
||||
name: 'caddress2',
|
||||
type: 'input-text',
|
||||
label: 'caddress2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '工作信息',
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
title: '工作信息',
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'cname',
|
||||
label: '公司名称:'
|
||||
},
|
||||
{
|
||||
name: 'caddress',
|
||||
type: 'input-text',
|
||||
label: '公司地址:'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
await wait(500);
|
||||
|
||||
expect(
|
||||
container.querySelector('.cxd-AnchorNav-link-child')
|
||||
).toHaveTextContent('基本信息1-1');
|
||||
|
||||
expect(
|
||||
container.querySelector('.cxd-AnchorNav-link.is-active')
|
||||
).toHaveTextContent('基本信息');
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
@ -568,6 +568,565 @@ exports[`Renderer:anchorNav 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:anchorNav with children 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Page"
|
||||
>
|
||||
<div
|
||||
class="cxd-Page-content"
|
||||
>
|
||||
<div
|
||||
class="cxd-Page-main"
|
||||
>
|
||||
<div
|
||||
class="cxd-Page-body"
|
||||
role="page-body"
|
||||
>
|
||||
<div
|
||||
class="cxd-AnchorNav cxd-AnchorNav--horizontal"
|
||||
>
|
||||
<ul
|
||||
class="cxd-AnchorNav-link-wrap"
|
||||
role="anchorlist"
|
||||
>
|
||||
<li
|
||||
class="cxd-AnchorNav-link is-active"
|
||||
>
|
||||
<a
|
||||
title="基本信息"
|
||||
>
|
||||
基本信息
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="cxd-AnchorNav-link cxd-AnchorNav-link-child"
|
||||
>
|
||||
<a
|
||||
title="基本信息1-1"
|
||||
>
|
||||
基本信息1-1
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="cxd-AnchorNav-link cxd-AnchorNav-link-child"
|
||||
>
|
||||
<a
|
||||
title="基本信息1-2"
|
||||
>
|
||||
基本信息1-2
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="cxd-AnchorNav-link"
|
||||
>
|
||||
<a
|
||||
title="工作信息"
|
||||
>
|
||||
工作信息
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div
|
||||
class="cxd-AnchorNav-section-wrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-AnchorNav-section"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel cxd-Panel--default cxd-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="cxd-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
基本信息
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
姓名:
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="name"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
邮箱:
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="email"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="email"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-footerWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-btnToolbar cxd-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary cxd-Button--size-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-AnchorNav-section"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel cxd-Panel--default cxd-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="cxd-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
基本信息1-1
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
cname1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="cname1"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
caddress1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="caddress1"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-footerWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-btnToolbar cxd-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary cxd-Button--size-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-AnchorNav-section"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel cxd-Panel--default cxd-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="cxd-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
基本信息1-2
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
cname2
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="cname2"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
caddress2
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="caddress2"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-footerWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-btnToolbar cxd-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary cxd-Button--size-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-AnchorNav-section"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel cxd-Panel--default cxd-Panel--form"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="cxd-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
工作信息
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
公司名称:
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="cname"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
公司地址:
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class=""
|
||||
name="caddress"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-footerWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-btnToolbar cxd-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary cxd-Button--size-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
提交
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Renderer:anchorNav with horizontal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
|
@ -3,7 +3,6 @@ import {Renderer, RendererProps} from 'amis-core';
|
||||
import {AnchorNav as CAnchorNav, AnchorNavSection} from 'amis-ui';
|
||||
import {isVisible, autobind} from 'amis-core';
|
||||
import {filter} from 'amis-core';
|
||||
import find from 'lodash/find';
|
||||
import {BaseSchema, SchemaClassName, SchemaCollection} from '../Schema';
|
||||
|
||||
/**
|
||||
@ -26,6 +25,11 @@ export type AnchorNavSectionSchema = {
|
||||
* 内容
|
||||
*/
|
||||
body?: SchemaCollection;
|
||||
|
||||
/**
|
||||
* 子节点
|
||||
*/
|
||||
children?: Array<AnchorNavSectionSchema>;
|
||||
} & Omit<BaseSchema, 'type'>;
|
||||
|
||||
/**
|
||||
@ -73,7 +77,7 @@ export interface AnchorNavProps
|
||||
sectionRender?: (
|
||||
section: AnchorNavSectionSchema,
|
||||
props: AnchorNavProps,
|
||||
index: number
|
||||
index: number | string
|
||||
) => JSX.Element;
|
||||
}
|
||||
|
||||
@ -94,7 +98,7 @@ export default class AnchorNav extends React.Component<
|
||||
renderSection?: (
|
||||
section: AnchorNavSectionSchema,
|
||||
props: AnchorNavProps,
|
||||
index: number
|
||||
index: number | string
|
||||
) => JSX.Element;
|
||||
|
||||
constructor(props: AnchorNavProps) {
|
||||
@ -107,21 +111,43 @@ export default class AnchorNav extends React.Component<
|
||||
if (typeof props.active !== 'undefined') {
|
||||
active = props.active;
|
||||
} else {
|
||||
const section: AnchorNavSectionSchema = find(
|
||||
let section: AnchorNavSectionSchema | null = this.getActiveSection(
|
||||
links,
|
||||
section => section.href === props.active
|
||||
) as AnchorNavSectionSchema;
|
||||
props.active,
|
||||
null
|
||||
);
|
||||
|
||||
active =
|
||||
section && section.href
|
||||
? section.href
|
||||
: (links[0] && links[0].href) || 0;
|
||||
}
|
||||
|
||||
this.state = {
|
||||
active
|
||||
};
|
||||
}
|
||||
|
||||
// 获取激活的内容区
|
||||
getActiveSection(
|
||||
links: Array<AnchorNavSectionSchema>,
|
||||
active: string | number | undefined,
|
||||
section: AnchorNavSectionSchema | null
|
||||
) {
|
||||
if (section) {
|
||||
return section;
|
||||
}
|
||||
links.forEach(link => {
|
||||
if (link.href === active) {
|
||||
section = link;
|
||||
} else {
|
||||
if (link.children) {
|
||||
this.getActiveSection(link.children, active, section);
|
||||
}
|
||||
}
|
||||
});
|
||||
return section;
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSelect(key: any) {
|
||||
this.setState({
|
||||
@ -132,7 +158,6 @@ export default class AnchorNav extends React.Component<
|
||||
@autobind
|
||||
locateTo(index: number) {
|
||||
const {links} = this.props;
|
||||
|
||||
Array.isArray(links) &&
|
||||
links[index] &&
|
||||
this.setState({
|
||||
@ -140,6 +165,46 @@ export default class AnchorNav extends React.Component<
|
||||
});
|
||||
}
|
||||
|
||||
renderSections(links: AnchorNavSectionSchema[], parentIdx?: string | number) {
|
||||
const {
|
||||
classnames: cx,
|
||||
classPrefix: ns,
|
||||
sectionRender,
|
||||
render,
|
||||
data
|
||||
} = this.props;
|
||||
|
||||
links = Array.isArray(links) ? links : [links];
|
||||
let children: Array<JSX.Element | null> = [];
|
||||
|
||||
links.forEach((section, index) => {
|
||||
if (isVisible(section, data)) {
|
||||
// 若有子节点,key为parentIdx-index
|
||||
let curIdx = (parentIdx ? parentIdx + '-' : '') + index;
|
||||
|
||||
children.push(
|
||||
/** 内容区 */
|
||||
<AnchorNavSection
|
||||
{...(section as any)}
|
||||
title={filter(section.title, data)}
|
||||
key={curIdx}
|
||||
name={section.href || curIdx}
|
||||
>
|
||||
{this.renderSection
|
||||
? this.renderSection(section, this.props, curIdx)
|
||||
: sectionRender
|
||||
? sectionRender(section, this.props, curIdx)
|
||||
: render(`section/${curIdx}`, section.body || '')}
|
||||
</AnchorNavSection>
|
||||
);
|
||||
if (section.children) {
|
||||
children.push(...this.renderSections(section.children, curIdx));
|
||||
}
|
||||
}
|
||||
});
|
||||
return children.filter(item => !!item);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
@ -159,27 +224,7 @@ export default class AnchorNav extends React.Component<
|
||||
return null;
|
||||
}
|
||||
|
||||
links = Array.isArray(links) ? links : [links];
|
||||
let children: Array<JSX.Element | null> = [];
|
||||
|
||||
children = links
|
||||
.map((section, index) =>
|
||||
isVisible(section, data) ? (
|
||||
<AnchorNavSection
|
||||
{...(section as any)}
|
||||
title={filter(section.title, data)}
|
||||
key={index}
|
||||
name={section.href || index}
|
||||
>
|
||||
{this.renderSection
|
||||
? this.renderSection(section, this.props, index)
|
||||
: sectionRender
|
||||
? sectionRender(section, this.props, index)
|
||||
: render(`section/${index}`, section.body || '')}
|
||||
</AnchorNavSection>
|
||||
) : null
|
||||
)
|
||||
.filter(item => !!item);
|
||||
let children = this.renderSections(links);
|
||||
|
||||
return (
|
||||
<CAnchorNav
|
||||
|
Loading…
Reference in New Issue
Block a user