我有3个不同标记的导航项,但都需要相同的功能 - 按顺序为其中的svg
paths
制作动画。听起来像使用HOC的好方案。但是,我无法通过从WrappedComponent中的ref调用的function
(activePaths)将refs推送到数组。我收到错误TypeError: _this2.activePaths is not a function
。这是我在没有使用HOC的情况下尝试为单个导航项目完成的工作codepen。
这是HOC的代码,它给了我错误。
export const withNavItem = WrappedComponent => class extends Component {
constructor() {
super();
this.activePaths = this.activePaths.bind(this);
this.markerPaths = [];
this.rendered = false;
}
componentDidMount() {
this.rendered = true;
this.animatePaths();
}
animatePaths() {
const { markerPaths } = this;
// prepare stroke to be animated
for (let i = 0; i < markerPaths.length; i++) {
const path = markerPaths[i];
const length = path.getTotalLength();
path.setAttribute('strokeDasharray', length);
path.style.strokeDashoffset = length;
}
// animate stroke
const markerDrawing = anime({
targets: markerPaths,
strokeDashoffset: [anime.setDashoffset, 0],
easing: 'easeInOutSine',
duration: 400,
delay(el, i) { return i * 150; },
direction: 'alternate',
loop: false,
});
}
activePaths(el, linkType) {
if (el === null || this.rendered) {
return;
}
this.markerPaths.push(el);
}
render() {
this.rendered = true;
return <WrappedComponent {...this.props} />;
}
};
export default withNavItem;
class NavItemHey extends React.Component {
render() {
return (
<div>
<span className="letter-holder">
<span className="letter">H</span>
<span className="letter-strokes letter-strokes--h">
<span className="h-left-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 106 306">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M59,0c0,0,0.1,114-0.5,195.8S58,314.5,58,314.5" />
</svg>
</span>
<span className="h-middle-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 118 106">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M0.1,58c0,0,33.5-0.1,66.8,0.5s63.2,0.5,63.2,0.5" />
</svg>
</span>
<span className="h-right-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 109 304">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M59,0c0,0,0.1,114-0.5,195.8S58,314.5,58,314.5" />
</svg>
</span>
</span>
</span>
<span className="letter-holder letter-e">
<span className="letter">E</span>
<span className="letter-strokes letter-strokes--e">
<span className="e-left-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 106 316">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M59,0c0,0,0.1,114-0.5,195.8S58,314.5,58,314.5" />
</svg>
</span>
<span className="e-top-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 134 105">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M0.2,51c0,0,24.5-0.1,57.8,0.5s75.2,0.5,75.2,0.5" />
</svg>
</span>
<span className="e-middle-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 127 103">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M0.2,51c0,0,24.5-0.1,57.8,0.5s75.2,0.5,75.2,0.5" />
</svg>
</span>
<span className="e-bottom-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 136 106">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M0.2,51c0,0,24.5-0.1,57.8,0.5s75.2,0.5,75.2,0.5" />
</svg>
</span>
</span>
</span>
<span className="letter-holder letter-y">
<span className="letter">Y</span>
<span className="letter-strokes letter-strokes--y">
<span className="y-left-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 196 232">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M58,0c0,42,13.8,71.5,37,117c24,47,52,80,52,116" />
</svg>
</span>
<span className="y-right-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 218 215">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M110.5,0.1c0,0,0.1,83.6-0.5,143.5c-0.5,60-0.5,90-0.5,90" />
</svg>
</span>
<span className="y-bottom-stroke letter-stroke">
<svg className="letter-stroke__svg" viewBox="0 0 106 122">
<path ref={el => this.activePaths(el)} className="letter-stroke__svg-path" d="M59,0.1c0,0,0.1,43.5-0.5,76.8S58,125.6,58,125.6" />
</svg>
</span>
</span>
</span>
</div>
);
}
};
export default withNavItem(NavItemHeyo);
这个codepen是一个采用不同路径按顺序为某些路径设置动画的示例,但我不确定是否可以复制此路径,因为我的路径是如此嵌套。
有没有人有任何想法?
答案 0 :(得分:2)
错误显示,因为子组件中的 this 表示子组件而不是HOC。为了能够使用这样的功能,它需要通过props传递给子组件。一些伪代码:
// HOC
...
render() {
this.rendered = true;
return <WrappedComponent {...this.props} activePaths={this.activePaths} />;
}
// WRAPPED COMPONENT
...
<path ref={el => this.props.activePaths(el)} />
答案 1 :(得分:0)
如果我正确理解了您的Codepen,只需在HOC中添加componentDidMount并在其中操作引用。
const withNavItem = InnerComponent => class extends React.Component {
constructor() {
super();
this.elementsArray = [];
}
// Added code
componentDidMount(){
this.elementsArray.forEach(el => {
// change appearance, animate, etc...
el.style.background = 'black'
})
}
// ^ added code
hocFunc(el, rendered) {
if (el === null || rendered) { // don't keep adding in refs after rendered first time
return;
}
this.elementsArray.push(el);
console.log(this.elementsArray);
}
render() {
return <InnerComponent {...this.props} elementsArray={this.elementsArray} hocFunc={this.hocFunc} />;
}
};
class NavItemOne extends React.Component {
constructor() {
super();
this.rendered = false;
}
componentDidMount() {
this.rendered = true;
}
render() {
return (
<div>
<div ref={el => this.props.hocFunc(el, this.rendered)} className="box a" />
<div ref={el => this.props.hocFunc(el, this.rendered)} className="box b" />
<div ref={el => this.props.hocFunc(el, this.rendered)} className="box c" />
<div ref={el => this.props.hocFunc(el, this.rendered)} className="box d" />
</div>
);
}
};
const NavItemOneWrapped = withNavItem(NavItemOne);
ReactDOM.render(
<NavItemOneWrapped />,
document.getElementById('root')
);