如何使用Ajax和JSON制作下拉菜单?

这是我用来在OpenCart中显示不同级别的类别菜单的代码。 它工作正常,但每次点击后它会产生越来越多的XHR finished loading: POSTXHR finished loading: GET s通过点击有时停止页面:

  _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; });  

HTML代码:

  

控制器代码:

 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'] = '
'; foreach ($categories as $category) { $data['x'] .= '
  • ' . $category['name'] . '
  • '; } $data['x'] .= '
    '; } 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 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代码来帮助我,我将非常感谢,因为我知道这些主题很少:-(

    您可以将post请求的结果存储在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 = "Test " + id + ""; 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; } 
       

    问题可能是您没有阻止锚标记的默认操作。 尝试添加event.preventDefault 。 这样浏览器将触发POST请求,而不是GET请求。

    此外,如果要通过ajax添加新的#mnav a元素,最好将事件绑定到文档而不是元素。

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

    在编写任何代码之前,您似乎需要制定有关您希望客户端和服务器进行通信的策略。

    我对您的问题的理解是“菜单会在每次点击时生成ajax请求,我不希望这样做。”

    但这就是你构建代码的方式:jQuery设置的菜单的onclick处理程序中有一个$.post()调用。

    另一种方法是将预先填充菜单所需的所有数据发送到客户端。 然后在每次单击菜单时,从已经在内存中的数据中提取,而不是发送ajax请求。

    我能想到有几种方法可以做到这一点。 您选择哪种策略取决于您对系统的舒适度和/或控制,以及页面速度的优先级

    1. 让服务器准备这些数据,并将其写入服务器端模板,以便数据立即可用,例如 。 这是最快的选择。
    2. 使用现有的ajax URL,但在页面加载时触发一系列ajax请求。 将所有结果发送到某个中央数据对象,如选项1中所示。一旦所有数据都返回,您的菜单将起作用。 这里的优点是您不必更改任何服务器端代码,但是大量的调用需要时间。
    3. 创建一个新的ajax URL,它能够在一个批处理中返回所有菜单数据。 这比选项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;} 
        

    我认为javascript代码方面可能存在问题。 我假设你的PHP和DB相关的代码正在抛出结果。 更好的解决方案是从这里下载ajax菜单加载器插件

    您可以将结果丢弃的PHP代码设置为文件,这样前端就不会打扰。 您可能需要遵循HTML结构,并且可以使用新的类名更新CSS以应用您的样式。 我希望能更快地解决你的问题。