2016-04-26 3 views
0

У меня есть сайт на базе ReactJS, который я хочу программно программировать. В основном рабочий цикл зацикливается:Имитация щелчка на динамически добавленном элементе с ванильным JavaScript

  1. Нажмите на элемент 1.
  2. Код веб-страницы динамически изменен, в течение которого добавлен элемент Element2.
  3. Нажмите на элемент 2.

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

У меня есть доступ к файлу JS, который отвечает за создание и изменение содержимого веб-сайта. Я могу найти код, который описывает элементы, которые меня интересуют, и при необходимости добавить дополнительных прослушивателей событий.

Я почти совершенно не знаком с клиентской разработкой, поэтому мой подход к решению этой задачи является чисто интуитивным. До сих пор моя идея заключалась в том, чтобы добавить прослушиватель событий для какого-то события «onAdded», которое будет срабатывать, когда элемент будет добавлен в DOM, и из этого прослушивателя вызовите прослушиватель «onclick» (или отправьте событие «щелчок» в каком-то другом путь). Однако я не могу найти никаких событий, которые указывали бы на добавление дерева DOM.

Таким образом, строго говоря, у меня есть два вопроса:

  1. описанный подход выше жизнеспособными (и адекватный)? Если да, то как именно я это выполню?
  2. Если я делаю все неправильно, то каков был бы правильный способ выполнить мою задачу?

Edit 1

По предложению Мэтью Хербста, я посмотрел в React методы управления жизненным циклом, как componentDidMount. Оказывается, элементы, которые я хочу автоматизировать нажатием, не являются независимыми компонентами React, но содержимое другого компонента добавлено внутри метода render с огромной цепочкой звонков createElement.

Так что теперь проблема переключается с обнаружения момента, когда конкретный элемент добавляется в структуру DOM, чтобы найти способ взаимодействия с ним.

Простой (и некрасиво) способ сделать это, так как я в настоящее время увидеть его, чтобы использовать window объект из componentDidMount, найдите элемент, Я хочу щелкнуть его атрибутом data-reactid (который является строка разделенных точками цифр который, как я могу сказать, генерируется динамически и отражает иерархию элементов), а затем отправляет требуемое событие DOM.

Возможно, это сработает, но если структура документа изменится, то значения data-reactid затем снова сломаются. Я бы предпочел как-то правильно отправить событие React's onClick, но я не знаю, как это сделать. Я попытался вызвать функцию, которая передается методу createElement в качестве значения свойства onClick от componentDidMount, но по какой-то причине он не работает.

Я также пробовал метод взаимодействия с DOM, описанный в this article, но в моем случае объект ReactDOM, похоже, не определен.

Поскольку я не являюсь разработчиком на стороне клиента, особенно не гуру React, я действительно не вижу всей картины того, как работает клиентская логика веб-сайта, и код, с которым я работаю, быть минифицированным/обфускационным, чтобы сделать его еще более трудным. Поэтому, если бы кто-нибудь мог предложить какие-либо конкретные предложения, не отправив меня прочитать всю документацию React, я был бы благодарен.

+0

Поскольку ваше приложение является React, вы должны быть очень заинтересованы в ['componentDidMount'] (https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount) и [' componentDidUpdate '] (https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate) методы жизненного цикла. –

+0

Все это может управляться государством. нажмите на элемент1 setState, данные изменились, потому что изменения состояния, которые делают элемент2 нажатием на этот setState, и цикл продолжается –

+0

@MatthewHerbst, спасибо за ваши предложения. Следуя по этому пути, я переформулировал свой первоначальный вопрос. За подробностями ознакомьтесь с изменениями публикации. – Semisonic

ответ

0

Хорошо, я не уверен, что на вопрос, столь же профаном, как и мой, следует ответить вообще, но похоже, что я понял.

Минимизированный/затемненный код, который я должен был иметь дело с еще видными особенностями React приложения, такие как объекты с серией обратных вызовов, как render, componentDidMount или componentDidUpdate. Так, как предположил Мэтью Хербст, я изучил то, что они делают.

элементов, нажав на которую мне нужно автоматизировать были созданы внутри render методов, с помощью длинных цепочек createElement вызовов, которые выглядели примерно так:

T["default"].createElement("li", null, T["default"].createElement("div", { 
    className: P["default"].img 
}, T["default"].createElement("img", { 
    src: n(600), 
    alt: "" 
}), T["default"].createElement("b", null , "+3")), T["default"].createElement("h4", null , "«Header text»", T["default"].createElement("b", null , "+3")), T["default"].createElement("p", null , "Description"), T["default"].createElement("div", { 
    className: P["default"].btn 
}, T["default"].createElement(A.Btn, { 
    mod: "info", 
    onClick: this._router.bind(this, "/gtr", "gtr") 
}, "Play"))) 

я отправил этот код в исходном сообщении, но тогда я действительно не понимал, что здесь происходит.

Оказывается, объект ссылается T["default"] является React объекта, а это означает, что T["default"].createElement вызовов были фактически эквивалентны React.createElement из них.

После этого помогло article by James K. Nelson, в котором объяснялось, что для нахождения определенного дочернего элемента компонента мне необходимо назначить ему атрибут ref. Мне нужно, чтобы получить доступ к этой кнопке «Play», так что я пытался добавить ref свойства, что выглядело как его объект дескриптора, поэтому он будет выглядеть

T["default"].createElement(A.Btn, { 
    mod: "info", 
    ref: "automatedElement1", 
    onClick: this._router.bind(this, "/gtr", "gtr") 
}, "Play") 

, и это сработало. Теперь, внутри метода componentDidUpdate я мог бы использовать код, как

if (this.refs.hasOwnProperty("automatedElement1")) { 
    var buttonElement = this.refs.automatedElement1; 
} 

К сожалению, я не совсем понимаю, как получить от этого объекта к его DOM отражения, но просто изучая его содержимое мне удалось найти недвижимость который соответствует значению атрибута data-reactid элемента HTML этой кнопки. Тогда я нашел не умнее решение, чем приобрести узел DOM элемента с помощью метода document.querySelector:

var buttonNode = document.querySelector('button[data-reactid="' + buttonElement._reactInternalInstance._rootNodeID + '"]'); 

if (buttonNode) { 
    buttonNode.click(); 
} 

Это может быть плохим решением, но это решение, которое я смог найти в моей ситуации, и она работает. Надеюсь, что это поможет любому, кто имел грубую встречу с приложением React и не знал, с чего начать.

+0

Рад, что вы поняли это. Вы должны знать, что [новейшая версия React, v15.0] (https://facebook.github.io/react/blog/2016/04/07/react-v15.html) удалила использование данных -reactid'. –

+0

@MatthewHerbst, какой будет идиоматический способ достижения одного и того же результата, но не полагаясь на использование «data-reactid»? – Semisonic

Смежные вопросы