简体   繁体   English

如何干掉我的jQuery代码并使其更具可读性/可维护性?

[英]How to DRY up my jQuery code and make it more readable/maintanable?

I'm starting to do a lot of jQuery programming. 我开始做很多jQuery编程。 I'm finding that my code is becoming a little hard to maintain and is not all that readable. 我发现我的代码变得有点难以维护并且不是那么可读。 My javascript is being included on every page of our web application, even though it is only used on one page. 我的javascript被包含在我们的Web应用程序的每个页面上,即使它只在一个页面上使用。 This has the benefits of having the javascript cached before loading the page, but I'm worried about accidentally creating functions with identical names (created by other programmers on my team). 这有利于在加载页面之前缓存javascript,但我担心意外创建具有相同名称的函数(由我团队中的其他程序员创建)。

I'm new to javascript, so there may be some basics that I'm missing. 我是javascript的新手,所以可能会有一些我缺少的基础知识。 What are some techniques that I can apply to the following code, as well as other code in the future to make my jQuery code more maintainable and easy to read? 我可以将哪些技术应用于以下代码,以及将来的其他代码,以使我的jQuery代码更易于维护和易读?

<script type="text/javascript">

$(document).ready(function(){
    $('#registration-information .copy-button').click(copyField);
});

function copyField(e) {

    e.preventDefault();

    var $tr = $(this).closest('tr');
    var originalText = jQuery.trim($tr.find('.contact-data').text());
    var newText = jQuery.trim($tr.find('.registration-data').text());
    var $button = $tr.find('.copy-button');
    var $loadingIcon = $('<span class="loading-icon"></span>').hide().insertAfter($button);
    var $undoLink = $('<a class="undo-link" href="#">Undo</a>').hide().insertAfter($button);
    var field = $button.attr('id');

    $undoLink.click(function(e){
        e.preventDefault();
        undoCopyField($tr, originalText);
    });

    $button.hide();
    $loadingIcon.show();

    $.ajax({
        url: '/registrations/copy-field-to-contact',
        data: {
            id: '<?php echo $registration->ID ?>',
            field: field,
            data: newText
        },
        success: function(data){
            if (data.success) {
                $loadingIcon.hide();
                $tr.find('.contact-data').html(newText);
                $tr.find('td.form_field_label').removeClass('mismatched');
                $tr.effect('highlight', 1000, function(){
                    $undoLink.fadeIn();
                });
            } else {
                displayErrorMessage(data.error);
                $loadingIcon.hide();
                $button.show();
            }
        },
        error: function(){
            displayErrorMessage('Unknown reason');
            $loadingIcon.hide();
            $button.show();
        }
    });
}

function undoCopyField($tr, originalText) {

    var $button = $tr.find('.copy-button');
    var $loadingIcon = $tr.find('.loading-icon');
    var $undoLink = $tr.find('.undo-link');
    var field = $button.attr('id');

    $undoLink.hide();
    $loadingIcon.show();

    $.ajax({
        url: '/registrations/copy-field-to-contact',
        data: {
            id: '<?php echo $registration->ID ?>',
            field: field,
            data: originalText
        },
        success: function(data){
            if (data.success) {
                $undoLink.remove();
                $loadingIcon.hide();
                $tr.find('.contact-data').html(originalText);
                $tr.find('td.form_field_label').addClass('mismatched');
                $tr.effect('highlight', 1000, function(){
                    $tr.find('.copy-button').fadeIn();
                });
            } else {
                displayErrorMessage(data.error);
                $loadingIcon.hide();
                $undoLink.show();
            }
        },
        error: function(){
            displayErrorMessage('Unknown reason');
            $loadingIcon.hide();
            $undoLink.show();
        }
    });
}

function displayErrorMessage(message) {
    alert('Sorry, there was an error while trying to save your changes: ' + message);
}
</script>

Update: There are numerous sections of this code sample with chunks of code that are almost identical. 更新:此代码示例的许多部分都包含几乎完全相同的代码块。 Specifically the AJAX calls. 特别是AJAX调用。 Those two blocks are essentially the same, except for the actions that take place after the call has completed. 除了呼叫完成后发生的操作外,这两个块基本相同。 I'd really like to figure out a way to DRY up those sections. 我真的想找出一种干涸这些部分的方法。

Two tips: 两个提示:

  • Use namespaces for your code to avoid name conflicts. 为代码使用名称空间以避免名称冲突。 There are of course no real namespaces in Javascript, but you can fake them using objects. 当然,Javascript中没有真正的命名空间,但您可以使用对象伪造它们。

` `

var MyCode=MyCode||{
        copyField:function (e){
    },
        someOtherFunction:function(){
    }
};

    $(document).ready(function(){
        MyCode.copyField(...);
    });
  • Put your javascript code one or more separate files (one per namespace), and use third party libraries like combres to combine them into one file, minify them and take care of proper caching. 将您的javascript代码放入一个或多个单独的文件(每个命名空间一个),并使用第三方库(如combres)将它们合并到一个文件中,缩小它们并处理正确的缓存。 It saves a lot of bandwidth and is cleaner than distributing all kinds of javascript functions across different pages. 它节省了大量带宽,比在不同页面上分发各种javascript函数更清晰。

One way to make your jQuery code cleaner and more maintainable is to break it into reusable jQuery plugins. 使jQuery代码更清晰,更易于维护的一种方法是将其分解为可重用的jQuery插件。 This allows you to encapsulate related functionality in a single file. 这允许您将相关功能封装在单个文件中。 Each plugin is effectively a namespace so you will avoid function name collisions. 每个插件实际上都是命名空间,因此您将避免函数名称冲突。 You can also pass arguments to the plugin to customize the behaviour on a page by page or case by case basis. 您还可以将参数传递给插件,以逐页或逐个案例地自定义页面上的行为。

There is a pretty good guide and template for writing plugins here 有一个很好的指导和模板写插件这里

The only real readability issue I see here is that you could declare your variables without using the var each time by using a comma after each variable: 我在这里看到的唯一真正的可读性问题是,您可以在每次变量后使用逗号每次都不使用var来声明变量:

var $tr = $(this).closest('tr'),
    originalText = jQuery.trim($tr.find('.contact-data').text()),
    newText = jQuery.trim($tr.find('.registration-data').text());

I've always found this a bit easier to read then just a series of vars. 我总是发现这更容易阅读,然后只是一系列变量。 To the eye, it looks like a code block that is started with var and ends when the indent returns. 从表面上看,它看起来像是以var开头的代码块,并在缩进返回时结束。

Aside from that, it all looks good. 除此之外,一切看起来都不错。

As a start... 作为一个开始......

Test drive the code using something like jsunit. 使用像jsunit这样的东西来测试代码。

Create small well named classes, with small well named methods. 使用名称很小的方法创建小型的命名类。 The name of the class will describe it's responsibilities. 该类的名称将描述它的职责。 The name of the method will describe it's responsibilities as well. 方法的名称也将描述它的职责。

Refactor to remove duplication. 重构以删除重复。

Limit the use of global scope. 限制使用全局范围。

Read Clean Code: A Handbook of Agile Software Craftsmanship [Paperback] Robert C. Martin (Editor) 阅读清洁代码:敏捷软件工艺手册[平装] Robert C. Martin(编辑)

You can use YUI namespace model, create a top level object (namespace) lets var STW = {}; 您可以使用YUI命名空间模型,创建顶级对象(namespace)让var STW = {}; use this namespace function to create other classes or namespace 使用此命名空间函数来创建其他类或命名空间

STW.namespace = function () {
            var a = arguments, o = null, i, j, d;
            for (i = 0; i < a.length; i = i + 1) {
                d = ("" + a[i]).split(".");
                o = STW;
                for (j = (d[0] == "STW") ? 1 : 0; j < d.length; j = j + 1) {
                    o[d[j]] = o[d[j]] || {};
                    o = o[d[j]];
                }
            }
            return o;
        }

lets takes some example in your first file use STW.namespace("STW.namespace1"); 让我们在你的第一个文件中使用STW.namespace(“STW.namespace1”); STW.Namespace1.class1=function(){ STW.Namespace1.class1 =函数(){

//your code } in other files STW.namespace("STW.namespace1.namespace2"); //你的代码}在其他文件STW.namespace(“STW.namespace1.namespace2”); STW.namespace1.namespace2.class2=function(){ STW.namespace1.namespace2.class2 =函数(){

//your code } //你的代码}

The stuff in the $.ajax parens is just a single argument like in any c-based function. $ .ajax parens中的东西只是一个参数,就像在任何基于c的函数中一样。

{} is JS's literal representation of an object. {}是JS对象的文字表示。 So if both cases have the same stuff between {} you could do this: 因此,如果两个案例在{}之间具有相同的内容,则可以执行此操作:

    options = {
        url: '/registrations/copy-field-to-contact',
        data: {
            id: '<?php echo $registration->ID ?>',
            field: field,
            data: newText
        },
        success: function(data){
            if (data.success) {
                $loadingIcon.hide();
                $tr.find('.contact-data').html(newText);
                $tr.find('td.form_field_label').removeClass('mismatched');
                $tr.effect('highlight', 1000, function(){
                    $undoLink.fadeIn();
                });
            } else {
                displayErrorMessage(data.error);
                $loadingIcon.hide();
                $button.show();
            }
        },
        error: function(){
            displayErrorMessage('Unknown reason');
            $loadingIcon.hide();
            $button.show();
        }
    }

And then for both: 然后两个:

$.ajax(options);

Now if there's a variation in the options for your next ajax call: 现在,如果您的下一个ajax调用的选项有变化:

Example #1 - just change the URL to google 示例#1 - 只需将URL更改为Google

options.url = "http://www.google.com";
$.ajax(options);

Example #2 - change id property of the data property (which is another object) Example#2 - 更改data属性的id属性(这是另一个对象)

options.data.id = "newID";

A word of caution on JQuery's selector syntax. 关于JQuery的选择器语法的警告。 Grabbing directly by ID is ideal. 直接通过ID抓取是理想的选择。 Grabbing just by class can be really slow in older versions of IE (which have no native getByClassName methods so there's more interpreter-level looping going on). 在旧版本的IE(没有本机getByClassName方法,因此有更多的解释器级循环)中,仅仅按类抓取可能会非常慢。 The ideal way to write a selector narrows down to the closest parent ID available first and if you can be explicit add the tag name to the follow-up class selector to narrow down further (getElementsByTagName is native and speedy). 编写选择器的理想方法会缩小到最接近的父ID,如果可以显式,则将标记名称添加到后续类选择器中以进一步缩小范围(getElementsByTagName是本机且快速的)。

So if we could rely on .copy-button being an input tag: 因此,如果我们可以依赖.copy-button作为输入标记:

$('#registration-information input.copy-button')

or we could rely on it being an input or an anchor tag 或者我们可以依赖它作为输入或锚标记

$('#registration-information input.copy-button, #registration-information a.copy-button')

those might be considerably faster options in IEs 6 and maybe 7 if there's a ton of HTML elements inside #registration-information. 如果在#registration-information中有大量的HTML元素,那么在IE 6中可能会有相当快的选择,也许可能是7。 I try to give IDs to all unique containers likely to stay that way such that I've always got IDs handy for more efficient JQuery selectors. 我尝试为所有可能保留这种方式的独特容器提供ID,以便我总是可以获得更有效的JQuery选择器的ID。

But whatever you do, avoid these: 但无论你做什么,请避免这些:

$('.copy-button')

That can choke IE 6 even on a largish html doc if there's enough of it going around. 如果有足够的它可以解决问题,那么即使是在一个较大的HTML文档上也可能会阻塞IE 6。 If you plan on using the results of a selector more than once, save it to a var. 如果您计划多次使用选择器的结果,请将其保存到var。 It's so concise it's easy to forget that these can be fairly resource intensive operations in some cases. 它非常简洁,很容易忘记在某些情况下这些操作可能是资源密集型操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM