Yii renderpartial (proccessoutput = true) Avoid Duplicate js request

我怕爱的太早我们不能终老 提交于 2019-11-27 19:32:13

To avoid including core scripts twice

If your scripts have already been included through an earlier request, use this to avoid including them again:

// For jQuery core, Yii switches between the human-readable and minified
// versions based on DEBUG status; so make sure to catch both of them
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;

If you have views that are being rendered both independently and as HTML fragments to be included with AJAX, you can wrap this inside if (Yii::app()->request->isAjaxRequest) to cover all bases.

To avoid including jQuery scripts twice (JS solution)

There's also the possibility of preventing scripts from being included twice on the client side. This is not directly supported and slightly more cumbersome, but in practice it works fine and it does not require you to know on the server side what's going on at the client side (i.e. which scripts have been already included).

The idea is to get the HTML from the server and simply strip out the <script> tags with regular expression replace. The important point is you can detect if jQuery core scripts and plugins have already been loaded (because they create $ or properties on it) and do this conditionally:

function stripExistingScripts(html) {
    var map = {
        "jquery.js": "$",
        "jquery.min.js": "$",
        "jquery-ui.min.js": "$.ui",
        "jquery.yiiactiveform.js": "$.fn.yiiactiveform",
        "jquery.yiigridview.js": "$.fn.yiiGridView",
        "jquery.ba-bbq.js": "$.bbq"
    };

    for (var scriptName in map) {
        var target = map[scriptName];
        if (isDefined(target)) {
            var regexp = new RegExp('<script.*src=".*' +
                                    scriptName.replace('.', '\\.') +
                                    '".*</script>', 'i');
            html = html.replace(regexp, '');
        }
    }

    return html;
}

There's a map of filenames and objects that will have been defined if the corresponding script has already been included; pass your incoming HTML through this function and it will check for and remove <script> tags that correspond to previously loaded scripts.

The helper function isDefined is this:

function isDefined(path) {
    var target = window;
    var parts = path.split('.');

    while(parts.length) {
        var branch = parts.shift();
        if (typeof target[branch] === 'undefined') {
            return false;
        }

        target = target[branch];
    }

    return true;
}

To avoid attaching event handlers twice

You can simply use a Javascript object to remember if you have already attached the handler; if yes, do not attach it again. For example (view code):

Yii::app()->clientScript->registerScript("view-script","
  window.myCustomState = window.myCustomState || {}; // initialize if not exists
  if (!window.myCustomState.liveClickHandlerAttached) {
    window.myCustomState.liveClickHandlerAttached = true;
    $('.link').live('click',function(){
       alert('test');
    })
  }
");

The cleanest way is to override beforeAction(), to avoid any duplicated core script:

class Controller extends CController {

  protected function beforeAction($action) {
        if( Yii::app()->request->isAjaxRequest ) {
            Yii::app()->clientScript->scriptMap['jquery.js'] = false;
            Yii::app()->clientScript->scriptMap['jquery-2.0.0.js'] = false;
            Yii::app()->clientScript->scriptMap['anything.js'] = false;
        }

        return parent::beforeAction($action);
  }

}

Note that you have to put the exact js file name, without the path.

marcovtwout

To avoid including script files twice, try this extension: http://www.yiiframework.com/extension/nlsclientscript/

To avoid attaching event handlers twice, see Jons answer: https://stackoverflow.com/a/10188538/729324

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!