Как переместить несколько элементов с помощью requestAnimationFrame (), не создавая новую функцию для каждого элемента - PullRequest
0 голосов
/ 26 июня 2019

Предисловие: это то, что я планирую использовать и добавить для различных веб-страниц.В связи с этим я не хочу использовать для этого какой-либо JQuery, отчасти потому, что многим страницам, на которых я его использую, больше ничего не понадобится (поэтому я использовал JQuery, наподобие наполнения ведра емкостью пятьдесят галлонов мукой, просто чтобы использоватьчайная ложка этой муки), и частично потому, что она предназначена для мобильных браузеров с редкими ресурсами.

Недостаточная эффективность JQuery может показаться не такой уж большой проблемой, особенно с учетом размера ее консолидированной библиотеки *Значение 1004 * меньше 31 МБ, но, согласно этой странице , это нечто столь же фундаментальное для JavaScript, как его вызов document.getElementById('foo'); почти в 16 раз быстрее в Chrome, чем эквивалент JQueries: $('#foo');.Кроме того, несмотря на то, что $('#foo'); быстрее в Firefox и Safari, чем в Chrome, document.getElementById('foo'); все еще в 10 раз быстрее в Safari и поразительно в 500 раз быстрее в Firefox.Хотя, если у вас есть источник с противоречивой информацией, не стесняйтесь публиковать его в комментариях и добавлять комментарии тем, кто уже это сделал.

У меня есть набор навигационных ссылок, которые я пытаюсь продвинуть вверхсо скоростью и относительно позиции относительно расстояния до первой навигационной ссылки.Чтобы помочь вам понять, что я имею в виду, вот анимация моей навигационной панели (выполненная с помощью функций JQuery slideUp & slideDown ), чтобы вы могли увидеть, как она работает (& заикается): JQuery Animated Nav Bar

Я также включу HTML-код панели навигации, если это поможет:

<nav>
    <ul id='nav'>
        <li><a href="index.php"><icon><img src="images/home-icon.png"></icon>Home</a></li>
        <li><a href="skillsets.php"><icon><img src="images/skills-icon.png"></icon>Skillsets</a></li>
        <li><a href="gallery.php"><icon><img src="images/gallery-icon.png"></icon>Gallery</a></li>
        <li><a href="about.php"><icon><img src="images/about-icon.png"></icon>About</a></li>
        <li><a href="contact.php" style='border-right:1px solid black;'><icon><img src="images/contact-icon.png"></icon>Contact</a></li>
    </ul>
</nav>

В моем файле JavaScript есть функция с именем prepareList()это просто для того, чтобы настроить список и свернуть его (перемещая все, кроме первой навигационной ссылки вверх).Чтобы предотвратить инициализацию prepareList() & любых используемых им переменных перед загрузкой HTML, все они содержатся в этой функции:

document.addEventListener("DOMContentLoaded", function(event) {/*all the code*/});

Теперь я включу свой prepareList()Функция JavaScript, а также инициализация и значения всех используемых переменных.Я достаточно хорошо прокомментировал это, чтобы вы могли понять это только из комментариев в коде, но я уточню, что я хочу сделать потом:

//I will consolidate the first three objects into one href variable when I get the program working
var ul = document.getElementsByTagName("nav")[0].children[0],
    li = ul.children,
    href = new Array(li.length),
    is404 = true,
    isDown = false;

var itterator;
for(itterator = 0; itterator < li.length; itterator++)
    href[itterator] = li[itterator].children[0];

prepareList();

function prepareList() {
    //add a plus to the first nav link making it more obvious that it's the button to open the nav
    href[0].innerHTML = href[0].innerHTML + "<span> +</span>";
    //hide the remaining nav links with animations that move them up, at a speed,
    //and to a postion, relative to how far they are from the first nav link
    var lastTick = +new Date();
    /*This function will be called for each nav link so they move at the same time
    navElement is one of the li elements, number is the number (index) of the li element,
    and number is negative if the list is collapsing (moving up)*/
    var tick = function(navElement, number) {
        var navElementStyleTop = parseFloat(navElement.style.top) + number * navElement.clientHeight * (new Date() - lastTick) / 1000;
        //navElement.style.top = (navElementStyleTop + number * navElement.clientHeight * (new Date() - lastTick) / 1000) + "px"; //milliseconds
        navElement.style.top = navElementStyleTop + "px";
        lastTick = +new Date();

        //requestAnimationFrame(tick) will only loop tick if the animation can be performed: http://www.javascriptkit.com/javatutors/requestanimationframe.shtml
        //setTimeout(tick, 1000/15) will force the animation to be performed if it's been more than 1/15th of a second in order to maintain persistance of motion
        if(number < 0){
            if (navElementStyleTop > number * navElement.clientHeight)
                requestAnimationFrame(tick(navElement, number)) || setTimeout(tick, 1000/15);
            else //To prevent rounding errors from messing up the final position
                navElement.style.top = (number * navElement.clientHeight) + "px";
        }
        else{
            if (navElementStyleTop < 0)
                requestAnimationFrame(tick(navElement, number)) || setTimeout(tick, 1000/15);
            else //To prevent rounding errors from messing up the final position
                navElement.style.top = "0px";   
        }
    };
    /*The for loop is to make this work no matter the number of links in the nav bar
    (as the function executed before this may add a link to the nav bar)*/
    for(itterator = 1; itterator < li.length; itterator++){
        //necessary for top to work
        href[itterator].style.position = "relative";
        //give top a value so this doesn't rely on the browser defaulting it to 0
        href[itterator].style.top = "0px";
        tick(href[itterator], (-1) * itterator);
    }
}

Если вы не видели проблемуЯ не могу винить тебя, это с requestAnimationFrame(tick(navElement, number)).Чтобы не жаловаться на рекурсию, она должна быть выполнена следующим образом: requestAnimationFrame(tick).Согласно этот ответ StackOverFlow , requestAnimationFrame является асинхронным, что означает, что «основной поток не ожидает возврата к запросу requestAnimFrame, прежде чем« продолжить работу с функцией.

что я должен передать по крайней мере number в функцию, чтобы функция знала, какой элемент он использует.Единственный способ сделать так, чтобы функция не требовала передачи каких-либо параметров, - это каждый раз инициализировать ее в цикле for.Мне действительно не нравится это решение, так как я хотел бы иметь возможность повторно использовать эту функцию, чтобы не тратить впустую циклы (и, вероятно, много памяти), воссоздавая его для каждой навигационной ссылки после первой.Итак, меня интересует, есть ли способ передать number во все функции тиков при сохранении асинхронного характера requestAnimationFrame.

Если у вас есть лучший способ, который намного эффективнее, чемФункции JQuery slideUp & slideDown , я весь в ушах.Возможно, у кого-то есть гораздо более эффективная версия JavaScript где-то в сети, но я ее не нашел.

Не стесняйтесь, дайте мне знать в комментариях, если вам нужна дополнительная информация, или если у меня есть какие-либо опечатки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...