组件加载后滚动到 Material 手风琴中特定的扩展面板

8
我们正在尝试滚动到<mat-accordion>中的特定<mat-expansion-panel>项目。问题是,ngAfterViewInit()在手风琴及其面板完全加载之前就被触发了。这意味着在手风琴加载时调用scrollIntoView()函数,页面大小会随后更改,使我们的滚动操作带我们到页面的错误位置。
我们还尝试了其他生命周期钩子,但它们都被调用得太早,没有帮助。有人对此问题有什么好的做法吗?
我们的源代码很简单,因为我们正在尝试实现非常基本的东西: landingpage.component.html
<mat-accordion>
   <mat-expansion-panel id="pangel-1">
    <mat-expansion-panel-header>
      <mat-panel-title>Lorem ipsum</mat-panel-title>
    </mat-expansion-panel-header>
    <p>
      Lorem ipsum dolor sit amet,
      consetetur sadipscing elitr,
      sed diam nonumy eirmod tempor invidunt...
    </p>
  </mat-expansion-panel>
  <mat-expansion-panel id="panel-2">
    <mat-expansion-panel-header>
      <mat-panel-title>Lorem ipsum</mat-panel-title>
    </mat-expansion-panel-header>
    <p>
      Lorem ipsum dolor sit amet,
      consetetur sadipscing elitr,
      sed diam nonumy eirmod tempor invidunt...
    </p>
  </mat-expansion-panel> 

  [ ... ] // more panels

</mat-accordion>

landingpage.component.ts

ngAfterViewInit() {
  this.scroll("panel-1");
}

scroll(id) {
  console.log(`scrolling to ${id}`);
  let el = document.getElementById(id);
  el.scrollIntoView();
}

1
请分享一些示例代码和模板,以便我们了解您的应用程序结构。Stackblitz示例将是理想的选择。 - G. Tranter
@G.Tranter 问题已更新。 - Alexander Belokon
3个回答

3
在我的例子中,我点击某个东西,它会打开一个占据屏幕一半的侧边导航栏,因此在点击函数中,我有以下逻辑:
if ($event) {
    setTimeout(() => $event.target.scrollIntoView({behavior: 'smooth', block: 'end'}), 1);
}

所以在你的例子中,你可以绑定到mat-expansion-panel上的afterExpand事件,并运行逻辑。


3
这是一个关于使用Angular Material 7的示例,可在StackBlitz上查看。您的技术很好,但需要注意以下几点:确保页面足够长,以便将面板定位在页面顶部,并确保不要拼写错误的面板ID。

很不幸,我误点了并将悬赏分配给了错误的答案,非常抱歉 - 今天工作时间有些长。但是,这确实是正确的答案,因为它提供了给定代码片段实际运行的证据。我们的组件相当大,所以问题似乎出在其他地方,我需要再仔细检查一下。 - Alexander Belokon

0
我遇到了同样的问题,并成功地以一种相当简洁和清晰的方式解决了它。我想这值得分享,以防其他人也能从中受益,并且可以扩展到之前的答案上。基本上,在状态改变和组件挂载后,我滚动到可视区域,并控制了动画的超时时间以及滚动函数。我处理的触发滚动的情况是,如果当前活动面板(只需将展开状态设置为true)等于当前渲染的面板。我希望所有先前的手风琴都是展开的,即不关闭其他面板。
import React, { useRef, useEffect } from 'react';
import { withStyles, makeStyles } from '@material-ui/core/styles';
import MuiAccordion from '@material-ui/core/Accordion';
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';

const ACCORDIAN_MIN_HEIGHT = 50;
const ACCORDIAN_V_MARGIN = 20;

const Accordion = withStyles((theme) => ({
    root: {
        // border: '1px solid rgba(0, 0, 0, .125)',
        // boxShadow: 'none',
        margin: `${ACCORDIAN_V_MARGIN}px 0`,

      '&:not(:last-child)': {
        borderBottom: 0,
      },
      '&:before': {
        display: 'none',
      },
      '&$expanded': {
        margin: `${ACCORDIAN_V_MARGIN}px 0`,
      },
    },
}))(MuiAccordion);
  
const AccordionSummary = withStyles((theme) => ({
    root: {
        minHeight: ACCORDIAN_MIN_HEIGHT,
        pointerEvents: 'none', // make accordian unlclickable
        '&$expanded': {
        minHeight: ACCORDIAN_MIN_HEIGHT,
        },
    },
}))(MuiAccordionSummary);

const AccordionDetails = withStyles((theme) => ({
    root: {
        padding: theme.spacing(2),
    },
}))(MuiAccordionDetails);

// Additional styles
const useStyles = makeStyles((theme) => ({
    accordianContent: {
        '& .MuiAccordionSummary-content' :{
            fontFamily: 'Gilroy',
            fontSize: '24px',
            transition: 'font-size 1s ease',
            margin: `${ACCORDIAN_V_MARGIN}px 0`,
        },
        '& .MuiAccordionSummary-content.Mui-expanded': {
            fontSize: '35px',
        },

    },
}));

  export default function AccordianSection(props) {
      
    const classes = useStyles();
    const thisAccordianRef = useRef(props.panel)

    const scrollQuestionIntoView = () => {
      setTimeout(() => thisAccordianRef.current.scrollIntoView({ behavior: 'smooth',block: "start", inline: "start" }),100)      
  }

  useEffect(() => {
    if (props.activeFormStep===props.panel) {
      scrollQuestionIntoView()
    }
  }, [props.activeFormStep])

      return (
          <>
            <Accordion ref={thisAccordianRef} expanded={props.expanded} 
                TransitionProps={{
                  timeout: 50
                }}
            >
                <AccordionSummary
                expandIcon={null}
                className={classes.accordianContent}
               >
                        {props.sectionHeading}
                </AccordionSummary>
                <AccordionDetails>
                    {props.children}
                </AccordionDetails>
            </Accordion>              
          </>
      )
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接