@Terinkov

Полоска под пунктами навигации?

Мне нужно узнать как сделать полоску которая находится в навигационном блоке под пунктом и "прыгает" от одного к другому при нажатии на другой пункт.
  • Вопрос задан
  • 201 просмотр
Пригласить эксперта
Ответы на вопрос 1
Моя версия на React

import React, { Component } from 'react';

import ReactDOM from 'react-dom';

import './testMenu.css';

class testMenu extends Component {

    constructor(props) {
        super(props);

        this.state = {
            menu: [
                {
                    title: 'Пункт 1',
                    active: true
                },
                {
                    title: 'Пункт 2',
                    active: false
                },
                {
                    title: 'Пункт 3',
                    active: false
                },
                {
                    title: 'Пункт 4',
                    active: false
                },
                {
                    title: 'Пункт 5',
                    active: false
                }
            ]
        };

        this._menuItems = [];
        this._menuHover = null;
        this._menuBlock = null;

    }

    shouldComponentUpdate(nextProps, nextState, nextContext) {
        if (this.state.menu != nextState.menu) {
            console.log('Should');
            return true;
        }

        return false;
    }

    componentDidMount() {
        this.getStyleMenuBlock()
    }

    componentDidUpdate() {
        this.getStyleMenuBlock();
    }

    handlerClickItem = (indexClick) => {
        let menuItems = this.state.menu.slice();

        menuItems.map((item, indexItem) => {
            if (indexItem == indexClick) {
                item.active = true;
            } else {
                item.active = false;
            }
        });

        this.setState({
            menu: menuItems
        })
    };

    getStyleMenuBlock = () => {

        let menuItems = this.state.menu.slice(),
            activeIndex = 0;

        let leftMenuBlock,
            leftMenuItem;

        menuItems.map((item, index) => {
            if (item.active) {
                activeIndex = index;
            }
        });

        leftMenuItem = ReactDOM.findDOMNode(this._menuItems[activeIndex]).getBoundingClientRect().left;
        leftMenuBlock = ReactDOM.findDOMNode(this._menuBlock).getBoundingClientRect().left;

        this._menuHover.style.transform = `translate3d(${ leftMenuItem - leftMenuBlock  }px, 0, 0)`;
        this._menuHover.style.width = ReactDOM.findDOMNode(this._menuItems[activeIndex]).getBoundingClientRect().width + 'px';
        this._menuHover.style.height = ReactDOM.findDOMNode(this._menuItems[activeIndex]).getBoundingClientRect().height + 'px';
    };

    render() {
        return (
            <div className='test-menu'>
                <ul className='test-menu__menu' ref={ref => { this._menuBlock = ref }}>
                    <React.Fragment>
                        {
                            this.state.menu.map((item, index) =>
                                <li
                                    key={ index }
                                    className={`test-menu__item ${ item.active ? 'test-menu__item_active' : '' }`}
                                    onClick={ () => this.handlerClickItem(index) }
                                    ref={ref => { this._menuItems[index] = ref; return true; }}
                                >{ item.title }</li>
                            )
                        }
                        <li
                            className='test-menu__hover'
                            ref={ref => { this._menuHover = ref }}
                        />
                    </React.Fragment>
                </ul>
            </div>
        )
    }
}

export default testMenu;


.test-menu {
    margin-top: 100px;
    display: flex;
}

.test-menu__menu {
    list-style-type: none;
    position: relative;
    display: flex;
    padding: 0;
    margin: 0;
    margin-left: 100px;
    margin-bottom: 100px;
    box-sizing: border-box;
}

.test-menu__item {
    padding: 5px 10px;
    border: 1px solid black;
    list-style-type: none;
    margin: 0 0 0 10px;
}

.test-menu__item_active {
    border: 1px solid red;
}

.test-menu__item:before {
    display: none;
}

.test-menu__block:before {
    display: none;
}

.test-menu__hover {
    position: absolute;
    left: 0;
    top: 0;
    width: 120px;
    height: 2px;
    background: red;
    opacity: 0.3;
    box-sizing: border-box;
    -webkit-transition: -webkit-transform 0.5s, width 0.5s, height 0.5s;
    transition: transform 0.5s, width 0.5s, height 0.5s;
    -webkit-transition-timing-function: cubic-bezier(1, 0.01, 0, 1);
    -webkit-transition-timing-function: cubic-bezier(1, 0.01, 0, 1.22);
    transition-timing-function: cubic-bezier(1, 0.01, 0, 1.22);
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы