Как использовать Ajax и JSON для создания выпадающего меню?

Вот код, который я использовал для отображения меню категорий в OpenCart с разными уровнями. Он работает, но после каждого щелчка он все больше и больше XHR finished loading: POST и XHR finished loading: GET s, которая останавливает страницу, иногда щелкая:

 <script type="text/javascript"> _url = ''; $(document).ready(function(){ $('#mnav a').on('click', function() { var cat = $(this).attr('id'); _url = '&category_id=' + cat; $.post('index.php?route=test/category/child' + _url, function(data) { if(data.length>10){ $('#mnav #sub').remove(); $(data).insertAfter($('#mnav #' + cat)); } }); }); }); $.ajaxPrefilter(function( options, original_Options, jqXHR ) { options.async = true; }); </script> 

Коды HTML:

 <div id="mnav" class="list-group"> <?php foreach ($categories as $category) { ?> <a id="<?php echo $category['category_id']; ?>" class="list-group-item active"><?php echo $category['name']; ?></a> <?php } ?> </div> 

Коды контроллера:

 <?php class ControllerTestCategory extends Controller { public function index() { if (isset($this->request->get['path'])) { $parts = explode('_', (string)$this->request->get['path']); } else { $parts = array(); } $data['category_id'] = 0; if (isset($parts[0])) { $data['category_id'] = $parts[0]; } else { $data['category_id'] = 0; } if (isset($parts[1])) { $data['child_id'] = $parts[1]; } else { $data['child_id'] = 0; } $this->load->model('catalog/cat'); $data['categories'] = array(); $categories = $this->model_catalog_cat->getCategories(0); foreach ($categories as $category) { $children_data = array(); $filter_data = array( 'filter_category_id' => $category['category_id'], 'filter_sub_category' => true ); $data['categories'][] = array( 'category_id' => $category['category_id'], 'name' => $category['name'], 'children' => $category['children'], 'products' => $category['products'], 'href' => $this->url->link('product/category', 'path=' . $category['category_id']) ); } $this->response->setOutput($this->load->view('test/category', $data)); } public function child() { if (isset($this->request->get['category_id'])) { $this->load->model('catalog/cat'); $data['categories'] = array(); $categories = $this->model_catalog_cat->getCategories($this->request->get['category_id']); $data['x'] = '<div id="sub">'; foreach ($categories as $category) { $data['x'] .= '<li>' . $category['name'] . '</li>'; } $data['x'] .= '</div>'; } else { $data['x'] = 'NA'; } $this->response->setOutput($this->load->view('test/category', $data)); } } 

Коды SQL:

 public function getCategories($parent_id = 0) { $sql = "SELECT c.category_id, c.parent_id, cd.name, (SELECT COUNT(DISTINCT ch.category_id) from category ch where ch.parent_id = c.category_id and cd.language_id = '" . (int)$this->config->get('config_language_id') . "') as children"; $sql .= " , (SELECT COUNT(DISTINCT p.product_id) FROM product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_category p2c ON (p2c.product_id = p.product_id) LEFT JOIN category_path cp ON (cp.category_id = p2c.category_id) WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND p.status = '1' AND p.date_available <= NOW()) AS items"; $sql .= " FROM category c LEFT JOIN category_description cd ON (c.category_id = cd.category_id) WHERE c.parent_id = '" . (int)$parent_id . "' AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c.status = '1' ORDER BY c.sort_order, LCASE(cd.name)"; $query = $this->db->query($sql); return $query->rows; } 

Я был бы очень признателен, если вы любезно поможете мне, предоставив все необходимые коды JavaScript, jQuery и JSON, потому что я знаю эти темы с небольшим 🙁

Related of "Как использовать Ajax и JSON для создания выпадающего меню?"

Вы можете сохранить результат почтового запроса в массиве javascript, чтобы его можно было повторно использовать, см. Ниже:

 var cachedObj = []; $(document).ready(function(){ $('#mnav a').on('click', function() { var cat = $(this).attr('id'); _url = '&category_id=' + cat; getData(cat, _url); //<-- Get data from ajax or cache }); }); //This function replaces the $.post call (just for example) function dummyPost(id, url){ //url should be used to make the post call var data = "<span class='sub'>Test " + id + "</span>"; return data; } function getData(id, url){ //Try to get data from cache var data; if(cachedObj[url]) { data = cachedObj[url]; console.log("Data retrived from cache"); } else { data = dummyPost(id, url); cachedObj[url] = data; console.log("Data retrived from post"); } $('#mnav .sub').remove(); //$(data).insertAfter($('#mnav #' + id)); $('#mnav #' + id).append($(data)); } 
 .sub{ color: red; font-weight: bold; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="mnav" class="list-group"> <a id="1" class="list-group-item active">One</a> <a id="2" class="list-group-item active">Two</a> <a id="3" class="list-group-item active">Three</a> </div> 

Проблема может заключаться в том, что вы не препятствуете действию якоря-тега по умолчанию. Попробуйте добавить event.preventDefault . Таким образом браузер будет POST запрос POST , а не GET .

Кроме того, было бы лучше привязать событие к документу не к элементам, если вы добавляете новые элементы #mnav a через ajax.

  $(document).ready( function() { $(document).on('click', '#mnav a', function( event ) { event.preventDefault(); // some code }); }); 

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

Мое понимание вашей проблемы заключается в том, что «меню генерирует запросы ajax с каждым щелчком, и я не хочу этого».

Но именно так вы создали код: обработчик onclick в меню, созданный jQuery, имеет в нем вызов $.post() .

Другой способ сделать это – отправить все данные, необходимые для заполнения меню клиенту спереди. Затем при каждом нажатии на меню извлекайте данные, которые уже находятся в памяти, а не отправляете запрос ajax.

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

  1. Попросите сервер подготовить эти данные и записать их в серверный шаблон, чтобы данные были сразу доступны, например, <script><?php echo 'var menuData = '.json_encode($my_data).'; ?></script> <script><?php echo 'var menuData = '.json_encode($my_data).'; ?></script> . Это самый быстрый вариант.
  2. Используйте существующие URL-адреса ajax, но при загрузке страницы сработайте ряд запросов ajax. Отправьте все результаты на некоторый центральный объект данных, как в варианте 1. После того как все данные вернутся, ваше меню будет работать. Преимущество здесь в том, что вам не нужно менять какой-либо код на стороне сервера, но для многих вызовов потребуется время.
  3. Создайте новый URL-адрес ajax, который сможет возвращать все данные меню в одной партии. Это будет быстрее, чем вариант 2, но вам придется работать на вашем сервере api.

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

 // DOM ready $(function() { $(document).off('click', '#mnav a').on('click', '#mnav a', function(e){ e.preventDefault(); // your stuff here }); }); 

Вы можете сделать это, выполнив следующие шаги.

создать раскрывающийся список с помощью javascript:

 function myFunction(){ var port_button = document.getElementById("port").value; if(port_button == 0){ var newhref; var newhrefid; var name = ["jquery ajax", "dropdown menu", "db"]; var links = ["api.jquery.com/jquery.ajax/", "www.w3schools.com/howto/howto_js_dropdown.asp", "www.w3schools.com/php/php_ajax_database.asp"]; var div=document.getElementById("myDropdown"); for(var i = 0; i<3; i++){ newhref= document.createElement("a"); newhref.href="http://"+links[i]; newhref.innerHTML= name[i]; newhrefid = "idhr_"+i; newhref.setAttribute('id', newhrefid ); div.appendChild(newhref); } document.getElementById("myDropdown").classList.toggle("show"); document.getElementById("port").value = "2"; } else if(port_button == 1){ document.getElementById("myDropdown").classList.toggle("show"); document.getElementById("port").value = "2"; } else{ document.getElementById("myDropdown").classList.toggle("hide"); document.getElementById("port").value = "1"; } } function filterFunction() { var input, filter, ul, li, a, i; input = document.getElementById("myInput"); filter = input.value.toUpperCase(); div = document.getElementById("myDropdown"); a = div.getElementsByTagName("a"); for (i = 0; i < a.length; i++) { if (a[i].innerHTML.toUpperCase().indexOf(filter) > -1) { a[i].style.display = ""; } else { a[i].style.display = "none"; } } } 
 .dropbtn { background-color: #4CAF50; color: white; padding: 16px; font-size: 16px; border: none; cursor: pointer; } .dropbtn:hover, .dropbtn:focus { background-color: #3e8e41; } #myInput { border-box: box-sizing; background-image: url('searchicon.png'); background-position: 14px 12px; background-repeat: no-repeat; font-size: 16px; padding: 14px 20px 12px 45px; border: none; } .dropdown { position: relative; display: inline-block; } .dropdown-content { display: none; position: absolute; background-color: #f6f6f6; min-width: 230px; overflow: auto; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1; } .dropdown-content a { color: black; padding: 12px 16px; text-decoration: none; display: block; } .dropdown a:hover {background-color: #ddd} .show {display:block;} 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="dropdown"> <button onclick="myFunction()" class="dropbtn">Dropdown</button> <div id="myDropdown" class="dropdown-content"> <input type="text" placeholder="Search.." id="myInput" onkeyup="filterFunction()"> </div> </div> <input type="hidden" id = "port" value = "0"> 

Я думаю, что может возникнуть проблема со стороны JavaScript. Я предполагаю, что ваш код, связанный с PHP и DB, корректно отображает результат. Лучшим решением будет скачать плагин загрузчика ajax menu здесь

Вы можете установить свой PHP-код для выдачи результата в файле, поэтому фронт не будет мешать вообще. Вам может потребоваться следовать структуре HTML, и вы можете обновить свой CSS с новым именем класса, чтобы применить свой стиль. Надеюсь, что это будет быстрее решить вашу проблему.