Angular中ngModel的$render的詳解


  在我開始着手ngModel的領域時候,有一個問題很令我糾結,那就是$render()到底是做什么的呢?查了很多資料都只是簡單的描述一下,這就令我很糾結了,終於在一個陽光明媚的晚上,我終於解決了這個大問題

  那么這個$render方法到底是干什么的呢?他的用處就是在$viewValue改變的時候可以重新綁定model數據,但是我們要注意一點($viewValue和DOM節點的value是不同的),我覺得他們的區別有點類似setTimeout和$timeout的區別,但是又不太一樣。ps:其實modelValue和綁定的數據也可以不同

Input里面模型的值:{{vm.modelTest}}
<input type="text" ng-model="vm.modelTest" model-render>
View Code
.directive('modelRender', function () {
        return {
            require: 'ngModel',
            link: function (scope, iElm, iAttrs, ngModelCtrl) {
                iElm.on('mouseenter', function () {
                    //嘗試注釋
                    iElm.val(1);
                    console.log(ngModelCtrl);
                    
                    //嘗試注釋
                    ngModelCtrl.$setViewValue(11);
                    console.log(ngModelCtrl);
                    
                    //嘗試注釋
                    ngModelCtrl.$render();
                    console.log(ngModelCtrl);
                }) 
            }
        }
    })
View Code

 我們分幾種情況分析

這是鼠標沒有經過指令的時候的樣子

  1.當我們使用js原生方法設置input的val值的時候,並且不執行$render函數,我們可以看到input里面的model值是沒有變化的,但是input的的value是變成了1,而且我們看到不僅model值沒有變化,ngModel的$viewValue和$modelValue同樣也沒有變化。我們可以得出結論 (input的value值不一定等於$viewValue)

   結果是這樣的

-----------------------------------------------------------------------------------------------------------------------  

  然后,我們嘗試在執行js原生改變value值之后,執行$render函數是個什么樣的狀況,

  

  看完上面的實驗之后我們發現input的value值並沒有發生變化,也就是說js原生改變input的value值是無效的,那么在這里我們就可以看到$render的功能了。

  我們可以大膽的預計$render的功能跟$apply的功能是一致的,我們在上一章講過,$apply是以viewValue為主,讓modelValue變成viewValue,也就是modelValue -> viewValue,那么$render是不是以modelValue為主,讓viewValue->modelValue呢? 

-------------------------------------------------------------------------------------------------------------------------

  2.接下來我們嘗試,使用ng原生改變 也就是說$setviewValue,是如何表現的呢?

   現在我們注釋掉js原生改變value的方法,而去使用$setViewValue,並且不執行$render函數,直接上結果,我們看到,執行完$setViewValue之后,無論是viewValue和modelValue都是已經同步了,但是input里面的值卻依然是test,在這里我們再次驗證了那個說法($viewValue和DOM節點的value是不同的)

  現在我們在$setViewValue之后使用,$render()看看是什么效果,

 

  大家發現了吧,$render的功能和$apply的功能極為相似,但是是不是很多人在講$render的時候,都會說model同步到view,我覺得這個說法不太對,我測試過在click事件用非常規手段改變controller中model的值,發現就算controller的值已經改變了,但是ngModel的值無論是viewValue還是modelValue都沒有變化,然后嘗試用$modelValue的屬性強行改變$modelValue,結果還是沒作用。我們下面來看看$render的源碼  

ctrl.$render = function() {
    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
  };

  這是其中一個,$render在不同的指令下的代碼都不太一樣,但是其作用基本一致,但是從這里我們就可以看出$render的到底在干什么事了。那么$render什么時候觸發呢?其實看你自己想什么時候調用它,你可以覆蓋他的方法,重寫,在$watch也好,$viewChange也好。默認的觸發事件一些特別input的value改變的時候例如單選,還有rollbackView()的時候

  另外一個真正體現$render執行事件的源代碼在這里,里面我寫了注釋,大家應該都能懂  

  

$scope.$watch(function ngModelWatch() {
  //解析ngModel的表達式,獲取內容
    var modelValue = ngModelGet($scope);

    // if scope model value and ngModel value are out of sync
    // TODO(perf): why not move this to the action fn?
  //判斷表達式的值是否跟modelValue一致
    if (modelValue !== ctrl.$modelValue &&
       // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
       (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
    ) {
    //更新modelValue的值
      ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
      parserValid = undefined;
    //獲取管道信息
      var formatters = ctrl.$formatters,
          idx = formatters.length;
    
      var viewValue = modelValue;
      while (idx--) {
        viewValue = formatters[idx](viewValue);
      }
    //如果viewValue和ModelValue不一致
      if (ctrl.$viewValue !== viewValue) {
        ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
        ctrl.$render();

        ctrl.$$runValidators(modelValue, viewValue, noop);
      }
    }
  //返回解析的表達式
    return modelValue;
  });
}];
  好了,$render就已經講完了,這是作者的原創帖,如轉載 請注明,最后貼段代碼感受下
  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM