前端analysis | 3w & 1h

《angular8》 - angular directive 升级ui-grid Ui更新问题

2020-04-28

ui-grid升级方案

  • 详情请移步这里ui-grid升级
  • 核心code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     @Directive({
    selector: 'hero-detail'
    })
    export class HeroDetailDirective extends UpgradeComponent {
    @Input() hero: Hero;
    @Output() deleted: EventEmitter<Hero>;

    constructor(elementRef: ElementRef, injector: Injector) {
    super('heroDetail', elementRef, injector);
    }
    }

问题

  • ui-grid 通过gridOptions选项设置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # js
    gridOption = {
    enableFiltering: true,
    enableGroupHeaderSelection: true,
    treeRowHeaderAlwaysVisible: false,
    data:[...],
    showColumnFooter: true,
    columnDefs: [...]
    }
    #html
    <div id="grid1" ui-grid="$ctrl.gridOptions" class="grid"></div>
  • 但是在通过angular upgradeComponent,针对ui-grid进行升级时,$digest不会被触发,界面ui不会更新

解决方案

  • 注入angularjs scope,手动调用$digest
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @Directive({
    selector: 'hero-detail',
    providers:{
    provide: '$scope',
    useFactory: (injector:Injector) => {
    ....
    },
    deps: ['$injector']}
    }
    })
    export class HeroDetailDirective extends UpgradeComponent {
    private _hero:Hero;
    private subject = new Subject();
    @Input()
    get hero(): Hero{
    return _hero;
    };
    set hero(data):Hero{
    this._hero = data;
    if(data){
    this.subject.next(data);
    }
    }
    @Output() deleted: EventEmitter<Hero>;

    constructor(elementRef: ElementRef, injector: Injector) {
    super('heroDetail', elementRef, injector);
    const scope = injector.get('$scope');
    this.subject.subscribe(res => {
    scope.$digest();
    });
    }
    }

angularjs

编译

  • 遍历dom,收集所有的指令
  • 根据指令类型,附带的特定逻辑,操作dom,然后dom整合

指令

dom元素的拓展

  • element names (E)
    1
    <my-dir></my-dir>
  • attributes (A)
    1
    <span my-dir="exp"></span>
  • class names (C)
    1
    <span class="my-dir: exp;"></span>
  • comments (M)
    1
    <!-- directive: my-dir exp -->
  • 通过restrict 属性,限制类型
    • ‘A’ - only matches attribute name
    • ‘E’ - only matches element name
    • ‘C’ - only matches class name
    • ‘M’ - only matches comment
  • 自定义指令
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     angular.module('app').directive('addOptions', function($compile) {
    return {
    priority: 100, // ngModel has priority 1
    terminal: true,
    compile: function(templateElement, templateAttributes) {
    templateAttributes.$set('ngModelOptions', '{debounce: 1000}');

    // The third argument is the max priority. Only directives with priority < 100 will be compiled,
    // therefore we don't need to remove the attribute
    var compiled = $compile(templateElement, null, 100);

    return function linkFn(scope) {
    compiled(scope) // Link compiled element to scope
    }
    }
    }
    });

    指令处理过程

  • 指令匹配;转化属性包含 :, -, or _为驼峰方式;dom元素,属性x-,data- 开头的,直接走读到后面的部分
    1
    2
    3
    4
    5
    6
    7
    8
     <div ng-controller="Controller">
    Hello <input ng-model='name'> <hr/>
    <span ng-bind="name"></span> <br/>
    <span ng:bind="name"></span> <br/>
    <span ng_bind="name"></span> <br/>
    <span data-ng-bind="name"></span> <br/>
    <span x-ng-bind="name"></span> <br/>
    </div>
  • 根据优先级进行排序
  • 编译指令,返回linkFn(scope)
  • 调用linkFn,得到dom元素
  • dom元素渲染到界面ui
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var $compile = ...; // injected into your code
    var scope = ...;
    var parent = ...; // DOM element where the compiled template can be appended

    var html = '<div ng-bind="exp"></div>';

    // Step 1: parse HTML into DOM element
    var template = angular.element(html);

    // Step 2: compile the template
    var linkFn = $compile(template);

    // Step 3: link the compiled template with the scope.
    var element = linkFn(scope);

    // Step 4: Append to DOM (optional)
    parent.appendChild(element);

    脏值检测

  • apply
    • 调用digest
    • 更新所有的scope
    • 传递一个function,更新前调用
  • digest
    • 遍历 watch list
    • 只更新当前的scope和子scope
    • 不需要传参数
  • watch
    • 根据指令,产生watch

参考

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏