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

2022-08-30 17:12:15

以下是我用来在OpenCart中显示具有不同级别的类别菜单的代码。它的工作原理,但是在每次单击后,它会产生越来越多的结果,并且有时会通过单击来停止页面:XHR finished loading: POSTXHR finished loading: GET

<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>

代码:

<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代码来帮助我,我将不胜感激,因为我对这些主题知之甚少:-(


答案 1

您可以将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 = "<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>

我已经制作了应该修改的函数,以便执行发布请求。dummyPost

您可以在我示例的日志中看到,当您第一次单击链接时,它会使用“post”检索他的子菜单,下一次,它将从缓存的数组中获取数据。cachedObj

我希望它能帮助你。再见。

更新:应用于您的代码应该是这样的:

<script type="text/javascript">

  var cachedObj = []; //<-- Add an array to cache submenus

  //Add a function to retrieves data from cache or REST
  function getData(url){
    //Try to get data from cache
    if(cachedObj[url]) {
      console.log("Data retrived from cache");
    }
    else {
      $.ajax({
         type: 'GET',
         url: 'index.php?route=test%2Fcategory%2Fchild' + url,
         success: function(data) {
               cachedObj[url] = data;
               console.log("Data retrived from post");
            }),
         async:false
      });
    }
    return cachedObj[url];
 }

 $(document).ready(function(){                
    $('#mnav a').on('click', function() {
        var cat = $(this).attr('id');
        var url = '&category_id=' + cat;

        var data = getData(url); //<-- Call the new function to get data
        if(data.length>10){
           $('#mnav #sub').remove();
           $(data).insertAfter($('#mnav #' + cat));
        }
    });
 });
</script>

我无法测试它,因此可能包含一些错误。


答案 2

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

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

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