Yii renderpartial (proccessoutput = true) избегайте дублирования запроса js

Im создание сайта, который работает с ajaxRequest, когда я нажимаю ссылку, он загружается с помощью ajaxRequest. Когда я загружаю, например, user / login actionLogin UserController, Я renderPartial представление с processOUtput в true так Яш нужна внутри, что вид будет, однако если я clientScriptRegister внутри представления событий, как я могу избежать создания scriptRegistered два или несколько в зависимости от ajaxRequest? Я пробовал Yii::app()->clientScript->isSCriptRegistered('scriptId') чтобы проверить, зарегистрирован ли скрипт, но кажется, что если вы использовали ajaxRequest,результат всегда false потому что это будет верно только после завершения рендеринга.

контроллер код

if (Yii::app()->request->isAjaxRequest)
{
   $this->renderPartial('view',array('model'=>$model),false,true);
}

Посмотреть Код

if (!Yii::app()->clientScript->isScriptregistered("view-script"))
   Yii::app()->clientScript->registerScript("view-script","
      $('.link').live('click',function(){
         alert('test');
     })
");

Если я запрашиваю контроллер в первый раз, он работает отлично (предупреждение 1 раз), но если я снова запрошу тот же контроллер без обновления моей страницы и просто с помощью ajaxRequest, предупреждение будет выводиться дважды, если вы нажмете на него (потому что он продолжает генерировать eventhough вы уже зарегистрировали его один раз)

Это то же самое, если у вас есть CActiveForm внутри представления с функциональностью jquery.. corescript yiiactiveform будет вызываться каждый раз, когда вы renderPartial.

3 ответов


чтобы избежать включения основных скриптов дважды

если ваши скрипты уже были включены через более ранний запрос, используйте это, чтобы избежать их повторного включения:

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

если у вас есть представления, которые отображаются как независимо, так и в виде HTML-фрагментов, которые будут включены в AJAX, вы можете обернуть это внутри if (Yii::app()->request->isAjaxRequest) для покрытия всех баз.

чтобы избежать включения сценариев jQuery дважды (решение JS)

существует также возможность предотвращение включения сценариев дважды на стороне клиента. Это не поддерживается напрямую и немного более громоздко, но на практике это работает нормально, и вам не нужно знать на стороне сервера, что происходит на стороне клиента (т. е. какие скрипты уже включены).

идея состоит в том, чтобы получить HTML с сервера и просто удалить <script> теги с помощью регулярных выражений заменить. Важным моментом является то, что вы можете обнаружить, если jQuery core скрипты и плагины уже загружены (потому что они создают $ или свойства на нем) и сделайте это условно:

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

есть карта имен файлов и объектов, которые будут определены, если соответствующий скрипт уже включен; передайте входящий HTML через эту функцию, и он будет проверять и удалять <script> теги, соответствующие ранее загруженным скриптам.

вспомогательную функцию isDefined это:

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

чтобы избежать прикрепление обработчиков событий дважды

вы можете просто использовать объект Javascript для запоминания, если вы уже прикрепили обработчик; если да, не прикрепляйте его снова. Например (код просмотра):

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');
    })
  }
");

самый чистый способ-переопределить beforeAction (), чтобы избежать дублирования основного скрипта:

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

}

обратите внимание, что вы должны поместить точное имя файла js без пути.


чтобы избежать включения файлов сценариев дважды, попробуйте это расширение:http://www.yiiframework.com/extension/nlsclientscript/

чтобы избежать присоединения обработчиков событий дважды, см. ответ Jons:https://stackoverflow.com/a/10188538/729324