jQuery - 代码重复

时间:2017-02-05 20:00:34

标签: javascript jquery

我是jQuery的绝对优势。我为我的应用程序编写了一些代码并将其放入.js文件中:

我应该如何避免jQuery中的代码重复?我应该在哪里存储我的.js代码(一个巨大的.js文件,几个较小或直接的html源代码)?

这是我的.js文件:

$(document).ready(function() {
    $("label[for='id_category1'], #id_category1, label[for='id_subcategory1'],#id_subcategory1 ").hide();
    $('select[name=subcategory]').empty();
    $('select[name=subcategory]').prepend('<option value="Not selected" selected disabled>Select Category...</option>');
    $('select[name=subcategory1]').empty();
    $('select[name=subcategory1]').prepend('<option value="Not selected" selected disabled>Select Category...</option>');
    // called when category field changes from initial value
    $('#id_group').change(function() {
        var $this = $(this);
        if ($this.find('option:selected').attr('value') == 'premium') {
            $("label[for='id_category1'], #id_category1").show();
            $("label[for='id_subcategory1'], #id_subcategory1").show();
        } else {
            $("label[for='id_category1'], #id_category1").hide();
            $("label[for='id_subcategory1'], #id_subcategory1").hide();
        }
    })


    $('#id_category').change(function() {
        var $this = $(this);
        if ($this.find('option:selected').index() !== 0) {
            category_id = $('select[name=category]').val();
            request_url = '/get_subcategory/' + category_id + '/';
            $.ajax({
                url: request_url,
                type: "GET",
                success: function(data) {
                    $('select[name=subcategory]').empty();
                    $.each(data, function(key, value) {
                        $('select[name=subcategory]').append('<option value="' + key + '">' + value + '</option>');
                    });
                }
            })
        }
    })
    $('#id_category1').change(function() {
        var $this = $(this);
        if ($this.find('option:selected').index() !== 0) {
            category_id = $('select[name=category1]').val();
            request_url = '/get_subcategory/' + category_id + '/';
            $.ajax({
                url: request_url,
                type: "GET",
                success: function(data) {
                    $('select[name=subcategory1]').empty();
                    $.each(data, function(key, value) {
                        $('select[name=subcategory1]').append('<option value="' + key + '">' + value + '</option>');
                    });
                }
            })
        }
    })
    $("label[for='id_keywords']").html("Keywords 0/100");
    $('#id_keywords').keyup(function() {
        var charsno = $(this).val().length;
        $("label[for='id_keywords']").html("Keywords (" + charsno + "/100)");
    });
    $("label[for='id_description']").html("Description 0/250");
    $('#id_description').keyup(function() {
        var charsno = $(this).val().length;
        $("label[for='id_description']").html("Description (" + charsno + "/2500)");
    });
});

感谢您提供有关初学者的任何线索。

4 个答案:

答案 0 :(得分:0)

始终将JavaScript与HTML分开。

始终根据单独的功能分离并加载单独的javascript文件。

然后尝试分解为MVC类型的架构。我一直在那里javascript文件长达2000行 - 它无法管理编辑和调试。

总是尝试使用类。

类架构在Javascript中是伪的,但是:

var view;
var model;
var ctrl;

/** - js_include_mvc.js
 * as per:
 * http://stackoverflow.com/questions/15192722/javascript-extending-class
 * provides the bare minimum facility to instantiate MVC objects if the base mvc classes are not subclassed
 * this ensures there is always js mvc
 *
 */
Ctrl.inherits(BaseCtrl);
function Ctrl(args) {
     BaseCtrl.apply(this, arguments);
     Ctrl.prototype.boot = function () {

     }
}

View.inherits(BaseView);
function View(args) {
     BaseView.apply(this, arguments);
     View.prototype.boot = function () {

     }
}

Model.inherits(BaseModel);
function Model(args) {
     BaseModel.apply(this, arguments);
     Model.prototype.boot = function () {

     }
}

然后例如:

function BaseView() {
    BaseView.prototype.somemethod = function () {
        //some functionality here
        return "I am a View";
    }
}

最后在全局页面脚本中调用它:

var view=new BaseView();
view.somemethod();

输出:

“我是一个观点”

我将类定义为BaseView,因为我放置了总是在这里重用的代码,但是BaseView类可以根据应用程序进一步扩展。因此,BaseView被用作我所有应用程序的主存储库,并根据需要对其进行扩展。

答案 1 :(得分:0)

我的一些代码注释需要重写,但我的Ajax类是这样的:

if (SERVER_INTERFACES == undefined) {
  var SERVER_INTERFACES = {};//global server array required for named multiple servers and asynch data callbacks
}

/** Ajax_js - communicates with the server to retreive data
 *
 * @param String newName is the name this class can reference for things like callbacks
 * @param Strin newUrl
 * @param String newNamedServer is the resource url defined as a php ajax server class
 * @returns {Ajax}
 */
function Ajax_m(newName, newUrl, newNamedServer) {
  this.namedServer = newNamedServer;
  this.interface_name = newName;
  this.url = newUrl;
  this.server_data; //allows a query to be given an id and the result data stored and accessible without having to manipulate into method arguments which might require data changes
  this.server_data = new Array(); //allows a query to be given an id and the result data stored and accessible without having to manipulate into method arguments which might require data changes
  this.request_index = 0;
  this.multiqueryindex = 0;
  this.multiqueryctrl = new Array();
  this.dataType = "json";
  this.reqType = "post";
  SERVER_INTERFACES[this.interface_name] = this;
  Ajax_m.prototype.request = function (requestobj, callback, optargs) {
    optargs = model.array_defaults(optargs, {runtagvals: {}});
    if (optargs.id == undefined) {
      this.request_index++;
    } else {
      this.request_index = optargs.id;
    }
    var request_id = this.request_index;
    if (typeof requestobj == "string") {
      //legacy was the requestobj as a string which is set to request and defaults assumed
      //attempt to parse ajaxRequestSubType as first 'word'
      var clauseend = requestobj.indexOf(" ");
      var ajaxRequestSubType = requestobj.substr(0, clauseend);
      requestobj = {ajaxRequestSubType: ajaxRequestSubType, request: requestobj, callback: callback, request_id: request_id};

    } else {
      //for legacy if callback and id are defined they are added but if in requestobj they will be overridden
      var args = {callback: callback, request_id: request_id};
      for (var r in requestobj) {
        args[r] = requestobj[r];
      }
      requestobj = args;
    }

    //ensure default settings
    var requestbuild = model.array_defaults(
            requestobj,
            {
              request: null,
              callback: "",
              errorCallback: null,
              request_id: null,
              interface_name: this.interface_name,
              responsedata: null,
              multirequestid: null,
              ajaxRequestSubType: "",
              ajaxRequestType: "database", //default to use database cfg definitions of site
              ismultiparent: false,
              _method: "PATCH"//for laravel5
            }
    );

    requestbuild.request = model.runtagreplace(requestbuild.request, optargs.runtagvals);

    this.server_data[request_id] = requestbuild;
    //debug in chrome as firebug fucks up badly with switch control
    switch (requestbuild.ajaxRequestSubType) {
      //control processes so no actual ajax requests are required
      case "multirequest_parent":
      case "multilrequest_submit":
        break;
      default:
        this.server_data[request_id].ajax = $.ajax({
          headers: {
            'X-CSRF-TOKEN': laravelCSRF//this is a constant from php JSCONSTANTS
          },
          url: this.url,
          type: this.reqType,
          data: requestbuild,
          dataType: this.dataType,
          success: function (server_response) {

            var requestobj = SERVER_INTERFACES[server_response.interface_name]; //.server_data[request_id];
            if (requestobj.server_data[request_id] != undefined) {//check existence - a reset might have been requested since query sent
              requestobj.setRequestResult(server_response.request_id, server_response.data);
              //check through request types to eventual detect a simple callback from client object
              switch (server_response.ajaxRequestSubType) {
                case "select":
                case "call":
                  if (server_response.flag_multiRequestChild) {
                    var parentinterface_name = requestobj.interface_name;
                    var parentinterface_id = server_response.multirequest_parent;
                    var multiobj =
                            SERVER_INTERFACES[parentinterface_name].
                            server_data[parentinterface_id];
                    multiobj.request_returned++;
                    if (multiobj.request_returned == multiobj.request_total) {
                      requestobj.multiRequestFinish(requestobj.server_data[request_id].multirequest_parent);
                    }
                  } else if (server_response.callback != "") {
                    eval(server_response.callback + "(" + server_response.request_id + ",'" + requestobj.interface_name + "')");
                  }
                  break;
                case "submit":
                  if (!server_response.ismultipart) {
                    if (server_response.callback != "") {
                      eval(server_response.callback + "(" + server_response.request_id + ")");
                    }
                  } else {
                    var multiobj = SERVER_INTERFACES[server_response.interface_name].server_data[requestobj.server_data[request_id].multisubmit_parent];
                    multiobj.submit_returned++;
                    if (multiobj.submit_returned == multiobj.submit_total) {
                      requestobj.multiSubmitFinish(requestobj.server_data[request_id].multisubmit_parent);
                    }
                  }
                  break;
                case "jscsv":
                  var downloadobj = SERVER_INTERFACES[server_response.interface_name].server_data[request_id];
                  requestobj.downloadrun(downloadobj);
                  break;

                default://need failover as cannot determine what to do
                  break;
              }
            } else {
              var faildata = "error";
            }
          },
          error: function (server_response) {
            //parse unhelpful error 'data' to relocate correct ajax request object
            var errordata = this.data.split("&");
            var intefacename;
            var requestid;
            var errorobj = {isajaxerror: true};
            for (var i in errordata) {
              var keyval = errordata[i].split("=");
              errorobj[keyval[0]] = keyval[1];
              if (errordata[i].indexOf("request_id=") != -1) {
                requestid = errordata[i].substr(errordata[i].indexOf("=") + 1);
              }
              if (errordata[i].indexOf("interface_name=") != -1) {
                interfacename = errordata[i].substr(errordata[i].indexOf("=") + 1);
              }
            }
            var parentobj = SERVER_INTERFACES[interfacename];
            var requestobj = parentobj.server_data[requestid];
            //new object required as out of scope

            errorobj["responseText"] = server_response.responseText;
            parentobj.setRequestResult(errorobj["request_id"], errorobj);
            eval(errorobj["callback"] + "(" + errorobj["request_id"] + ")");
          }
        });
        break;
    }
    return request_id;
  }

  /*
   * handles ajax where data is not expected back such as an insert statement or email send
   * but can expect a response message such as 'ok' or an error message
   */
  Ajax_m.prototype.submit = function (type, submitdata, callback) {
    this.request({ajaxRequestSubType: "submit", type: type, submitdata: submitdata, ismultipart: false, callback: callback});
  }

  /*
   * 'multiSubmit' handles ajax where data is not expected back such as an insert statement or email send
   * but can expect a response message such as 'ok' or an error message
   * EXAMPLE
   var multisub = [
   {
   type: "update",
   data: {
   table: "[xondbs1].stats.dbo.a_ppuser",
   values: {'email': 'tim'},
   matchfield: 'keyval', matchvalue: 'Q00010017'
   }
   },
   {
   type: "update",
   data: {
   table: "[xondbs1].stats.dbo.a_ppuser",
   values: {'email': 'tim'},
   matchfield: 'keyval', matchvalue: 'Q00010017'
   }
   }
   ];
   ajaxdbobj.multiSubmit(multisub, "callbackfunctionname");
   */
  Ajax_m.prototype.multiSubmit = function (submitobject, callback) {
    var parent_request_id = this.request({ajaxRequestSubType: "multisubmit_parent", submit_total: count(submitobject), submit_returned: 0, id_list: [], submit: {}, response: {}, callback: callback});
    for (var s in submitobject) {
      var child_request_id = this.request({
        ajaxRequestSubType: "submit",
        multisubmit_parent: parent_request_id,
        ismultipart: true,
        type: submitobject[s].type,
        submitdata: submitobject[s].data
      });
      this.server_data[parent_request_id].id_list[child_request_id] = s;
    }
    return parent_request_id;
  }

  /*
   * sets up mutli queries to only run callback when all complete
   * the requestobject is key=>query assoc to which results are assign the same key
   * when all results complete the callback is run giving the request_id in the normal way
   * to return the multi result object
   */
  Ajax_m.prototype.multiRequest = function (requestobject, callback) {
    var parent_request_id = this.request({ajaxRequestSubType: "multirequest_parent", request_total: count(requestobject), request_returned: 0, id_list: [], request: {}, data: {}, callback: callback});
    for (var r in requestobject) {
      /*var child_request = {
       request: requestobject[r],
       ajaxRequestSubType: "multirequest_child",

       }*/
      var child_request = requestobject[r];
      child_request.multirequest_parent = parent_request_id;
      child_request.flag_multiRequestChild = true;
      var child_request_id = this.request(child_request);
      this.server_data[parent_request_id].id_list[child_request_id] = r;
    }
    return parent_request_id;
  }

  /*
   * sets up facility for javascript to download data locally
   * there is no callback facility required as this is a one-way request
   * with a url returned pointing to the resultant file, this is ultimately sent as a new
   * window request to the file which will be handled on the native machine settings
   *
   * for integrity and security the server sets a unique filename ending
   *
   * First a meta query is sent to process what action to take - eg inform that data is emailed when ready if a length query
   * This is then fed back to the user as to what is happening before the actual query can begin.
   * @param type determines what download process should be used
   * @param dataArgs determines how the data is retrieived
   */
  Ajax_m.prototype.requestDownload = function (fileprefix, type, downloadData) {
    view.dialogOpen({
      title: "Download",
      dialogbody: "preparing download . . .",
      closeButton: false//change to false after test
    });
    this.request({ajaxRequestType: "requestDownload", fileprefix: fileprefix, ajaxRequestSubType: type, downloadData: downloadData});
    //this.server_data[downloadid].callbacktype = action;
  }

  /*
   * opens url to processed data downloadRequest in a new window / tab
   */
  Ajax_m.prototype.downloadrun = function (reqobj) {
//getRequestResult
    var meta = this.getRequestResult(reqobj.request_id);
    switch (reqobj.ajaxRequestSubType) {
      case "jscsv":
        view.dialogOpen({
          title: "Download",
          dialogbody: "Your file download has finished processing.<br />Please ensure you have popups enabled for this site to be able to access the file.",
          closeOK: true
        });
        window.open(meta.downloadurl, "download");
        break;
      case "dbcsv":
        view.dialogOpen({
          title: "Download",
          dialogbody: meta.msg,
          closeOK: true
        });
        this.request({ajaxRequestSubType: "downloadrun", filename: reqobj.filename, type: reqobj.type, downloadsource: reqobj.downloadsource}, '');
        break;
    }
  }

  /*
   * kills data (returning requested will be ignored)
   */
  Ajax_m.prototype.reset = function () {
    for (var s in this.server_data) {
      if (this.server_data[s].ajax) {
        this.server_data[s].ajax.abort();
      }
    }
    this.server_data = new Array();
    this.request_index = 0;
  }

  /*
   * relates misc data to query eg
   */
  Ajax_m.prototype.setMisc = function (request_id, miscobject) {
    this.server_data[request_id].misc = miscobject;
  }

  /*
   * gets misc data to query eg
   */
  Ajax_m.prototype.getMisc = function (request_id) {
    return this.server_data[request_id].misc;
  }

  /*
   * get orig query sent
   */
  Ajax_m.prototype.setAjaxRequestType = function (type) {
    this.reqType = type;
  }

  /*
   * get orig query sent
   */
  Ajax_m.prototype.setDataType = function (type) {
    this.dataType = type;
  }

  /*
   * get orig query sent
   */
  Ajax_m.prototype.getRequest = function (request_id) {
    return this.server_data[request_id].request;
  }

  /*
   * return result data for given request id
   */
  Ajax_m.prototype.getRequestResult = function (id) {
    var data;//leave as undefined so code fails in the client
    if (this.server_data[id]) {
      data = this.server_data[id].data;
    }
    return data;
    //return data;
  }

  /*
   * return result data for given request id indexed by a field name
   * if its not unique there will be data loss and a 'distinct' set will be returned
   */
  Ajax_m.prototype.getRequestResultByCol = function (id, colname) {
    var reqdata = this.getRequestResult(id);
    var data = {};
    for (var r in reqdata) {
      data.r[colname] = data.r;
      delete data.r[colname][colname];
    }
    return data;
    //return data;
  }

  /**
   * return a single value for given request id, if request id did actual generate
   * multiple values then only the first is returned
   * if this was a multirequest, the named key of the multi request is required
   */
  Ajax_m.prototype.getRequestValue = function (id, multi_id) {
    var retval;
    if (!this.server_data[id].ismultiparent) {
      retval = this.server_data[id].data[0];
    } else {
      retval = this.server_data[id].data[multi_id][0];
    }
    if (retval == undefined) {
      retval = null;
    }
    return retval;
  }



  /*
   * removes a query and data from memory
   */
  Ajax_m.prototype.deleteRequest = function (request_id) {
    delete this.server_data[request_id];
  }


  Ajax_m.prototype.error = function (serverData, st, ert) {
//all errors should have been handled, but just in case
    var errorReport = "error";
    errorReport += st;
    alert("error");
  }

  /**********************************************************************************************************
   INTENDED AS PRIVATE FUNCTIONS
   **********************************************************************************************************/

  /*
   * sets result data for this instance for given query id - eliminates the need  for eval unknown ajax data
   */
  Ajax_m.prototype.setRequestResult = function (request_id, data) {
    this.server_data[request_id].data = data;
  }

  /*
   * compiles the data from the multi query parts into the array entry referenced by the query_index returned
   * from client code calling the multiquery function. This also allows the required callback with a reference id to this data
   */
  Ajax_m.prototype.multiRequestFinish = function (multirequestid) {
    var requestobj = this.server_data[multirequestid];
    var multidata = {};
    var compactdata;
    for (var i in requestobj.id_list) {
      requestobj.data[requestobj.id_list[i]] = this.getRequestResult(i);
      this.deleteRequest(i);
    }
    eval(requestobj.callback + "(" + multirequestid + ")");
  }

  /*
   * finalises multisubmit and runs callback
   */
  Ajax_m.prototype.multiSubmitFinish = function (multirequestid) {
    var requestobj = this.server_data[multirequestid];
    var multidata = {};
    var compactdata;
    for (var i in requestobj.id_list) {
//requestobj.data[requestobj.id_list[i]] = this.getRequestResult(i);
      this.deleteRequest(i);
    }
    eval(requestobj.callback + "(" + multirequestid + ")");
  }

}

答案 2 :(得分:0)

您的代码中有很多重复。与@Datadimension 相反,我没有完全重构您的代码,而是试图向您展示参数化一些表达式和函数的方法:

$(document).ready(function() {
 var labcatsubcat1=
 $("label[for='id_category1'],#id_category1,label[for='id_subcategory1'],#id_subcategory1 ")
    .hide();
 $('select[name=subcategory],select[name=subcategory1]')
    .html('<option value="Not selected" selected disabled>Select Category...</option>');

 // called when category field changes from initial value:
 $('#id_group').change(function() {
   labcatsubcat1.toggle($(this).val()=='premium');
 })

 $('#id_category,#id_category1').change(function() {
        var $this = $(this), postfix=this.id.match(/1*$/)[0];
        if ($this.find('option:selected').index() > 0) {
            category_id = $('select[name=category'+postfix+']').val();
            request_url = '/get_subcategory/' + category_id + '/';
            $.ajax({
                url: request_url,
                type: "GET",
                success: function(data) {
                    $('select[name=subcategory'+postfix+']').empty();
                    $.each(data, function(key, value) {
                        $('select[name=subcategory'+postfix+']').append('<option value="' + key + '">' + value + '</option>');
                    });
                }
            })
        }
 });
 ["keywords,Keywords,100","description,Description,250"].forEach(e=>{
    var[id,nam,len]=e.split(",");
    $("label[for='id_"+id+"']").html(nam+" 0/"+len);
    $('#id_'+id).keyup(function() {
        var charsno = $(this).val().length;
        $("label[for='id_"+id+"']").html(nam+" (" + charsno + "/"+len+")");
    });
 });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

不幸的是,这(还)不是一个工作片段,因为您没有发布您的 HTML ...

关于 postfix 的简短说明:此变量将保存字符串 "1""",具体取决于 this 是指 #id_category1 还是#id_category DOM 元素。

答案 3 :(得分:-1)

我要做的一件事就是结合两个AJAX请求。您可以为change处理程序使用多个选择器。像$('#id_category', '#id_category1').change(etc...这样的东西。我相信你可以找到一种方法来准确定位哪一个正在处理哪个请求。您可以为其他函数以及the docs使用多个选择器。

如果文件相对较短(约100 - 200行),我认为您可以将所有内容保存在一个地方。否则,绝对将函数分成文件,然后根据需要require。你可以使用requireJS。