React组件中如何为多个按钮批量绑定MDCRipple.attachTo
解决MDCRipple仅第一个按钮生效的更优方案
嘿,我明白你的困扰——当初我第一次用MDCRipple的时候也踩过这个querySelector只拿第一个元素的坑!你现在通过遍历数组加id的方法确实能解决问题,但确实有更简洁、更符合React风格的实现方式,不用手动管理id或者遍历原数组~
方案1:用querySelectorAll批量获取元素
直接获取所有带.mdc-button类的元素,然后逐个绑定Ripple,这是最直接的改进:
componentDidMount() { // 获取页面中所有mdc-button元素 const buttonElements = document.querySelectorAll('.mdc-button'); // 遍历每个元素绑定Ripple buttonElements.forEach(button => MDCRipple.attachTo(button)); }
注意:
querySelectorAll返回的是NodeList,现代浏览器原生支持forEach;如果需要兼容旧版浏览器,可以转成数组再遍历:Array.from(buttonElements).forEach(...)
方案2:用React Ref实现组件内DOM查询(更推荐)
直接全局查询DOM可能会和其他组件的元素冲突,用React的Ref来限定查询范围更安全,也更符合组件化思想:
class NavBar extends Component { constructor(props) { super(props); this.state = { links }; // 创建容器Ref this.navSectionRef = React.createRef(); } componentDidMount() { // 只在当前组件的容器内查询按钮 if (this.navSectionRef.current) { const buttons = this.navSectionRef.current.querySelectorAll('.mdc-button'); buttons.forEach(button => MDCRipple.attachTo(button)); } } render() { return ( {/* 给容器绑定Ref */} <section ref={this.navSectionRef}> {this.state.links.map((link, i) => { return ( <StyledLink key={i} to={link.url}> <StyledButton className="mdc-button"> <StyledIcon className="material-icons">{link.icon}</StyledIcon> <StyledTypography className="mdc-typography--caption"> {link.title} </StyledTypography> </StyledButton> </StyledLink> ); })} </section> ); } }
这种方式的好处是:查询范围被限制在当前组件的DOM内,不会意外操作到其他组件的按钮,代码的封装性更好。
方案3:封装独立的MDCRipple按钮组件(最佳实践)
如果你的项目中会多次用到带Ripple效果的按钮,把按钮封装成独立组件是最优雅的方式,每个按钮自己负责初始化Ripple:
// 封装带Ripple的按钮组件 class MDCRippleButton extends Component { constructor(props) { super(props); this.buttonRef = React.createRef(); } componentDidMount() { // 组件挂载后自动绑定Ripple MDCRipple.attachTo(this.buttonRef.current); } render() { // 透传所有props和子元素 const { children, ...restProps } = this.props; return ( <StyledButton ref={this.buttonRef} className="mdc-button" {...restProps}> {children} </StyledButton> ); } }
然后在NavBar组件中直接使用这个封装好的按钮:
class NavBar extends Component { constructor(props) { super(props); this.state = { links }; } render() { return ( <section> {this.state.links.map((link, i) => { return ( <StyledLink key={i} to={link.url}> <MDCRippleButton> <StyledIcon className="material-icons">{link.icon}</StyledIcon> <StyledTypography className="mdc-typography--caption"> {link.title} </StyledTypography> </MDCRippleButton> </StyledLink> ); })} </section> ); } }
这种方式完全消除了父组件的DOM操作逻辑,代码模块化程度更高,后续修改Ripple逻辑或者复用按钮都非常方便。
内容的提问来源于stack exchange,提问作者Steven Creaney
相关产品推荐
相关产品推荐

