【问题标题】:Keep my code DRY for `$onInit` and `$onChanges` methods为 `$onInit` 和 `$onChanges` 方法保持我的代码干燥
【发布时间】:2019-01-26 23:34:48
【问题描述】:

我的几乎所有组件中都重复了一段代码:

import {deviceCommands} from "../../../core/data/Commands";


let _generalProperties = {
    'deviceName': deviceCommands.NAME.key,
    'deviceModel': deviceCommands.MODEL.key
};

export default class GeneralDeviceSettingsCtrl {
    constructor($scope) {
        let $ctrl = this;
        $ctrl.$onChanges = function (changes) {
            for(let prop in _generalProperties) {
                $ctrl[prop] = $ctrl.test.vm.data[_generalProperties[prop]];
            }
        };

        $ctrl.$onInit = function () {
            for(let prop in _generalProperties) {
                $scope.$watch(() => $ctrl.test.vm.data[_generalProperties[prop]],
                    (newValue, oldValue) => {
                        if (newValue !== oldValue) {
                            $ctrl[prop] = $ctrl.test.vm.data[_generalProperties[prop]];
                        }
                    });
            }
        };
    }
}

唯一不同的是_generalProperties 变量,这是我的观点所特有的。

如何保持干燥? 做一个基类?使用装饰器?

【问题讨论】:

  • 扩展基类是一个简单而明显的模式。在我自己的许多项目中,某些类别的组件最终都是以这种方式处理的。
  • 为什么在构造函数中给对象附加方法,而不是在类中定义方法?
  • 您是在询问 _generalProperties 吗?没有特别的原因,我希望我的课程尽可能短,并将内容保留给用户与视图的交互
  • 不,我的意思是你在构造函数中做$ctrl.$onInit = ...。您可以在构造函数之外和在类中定义类的方法。
  • 并非如此,在构造函数之外定义它们似乎更简洁。另外,这些方法在原型上进行并且只创建一次,但我假设您不会多次创建此控制器。

标签: javascript angularjs ecmascript-6 dry angularjs-components


【解决方案1】:

我认为有很多不同的方法可以解决这个问题,但如果你坚持使用类和继承,你可以将 _generalProperties 提供给你的父构造函数并重用整个实现。

例如:

export class BaseSettingsComponent {
    constructor(properties){
        this._properties = properties;
    }

    $onInit(){ /* ... implement base component stuff*/ }
}

然后,在每个使用相同组件逻辑的页面上,您可以扩展基类,将属性提供给父类并让基类完成工作。

import { BaseSettingsComponent } from '../common/base-settings-component.js';

let _generalProperties = {
    'deviceName': deviceCommands.NAME.key,
    'deviceModel': deviceCommands.MODEL.key
};

export class GeneralDeviceSettingsCtrl extends BaseSettingsComponent {
    constructor(){
        super(_generalProperties);
    }

    $onInit(){ super.$onInit(); /* ... implement base component stuff*/ }
}

使用此方法时要记住的重要一件事是,如果您需要在子类上实现 $onInit$onChanges,则必须调用 super.$onInit() 否则您会因为覆盖。

最后,为了更简洁的代码,您还可以丢弃 _generalProperties 的声明,将其直接提供给 super 构造函数。

import { BaseSettingsComponent } from '../common/base-settings-component.js';

export class GeneralDeviceSettingsCtrl extends BaseSettingsComponent {
    constructor(){
        super({
            'deviceName': deviceCommands.NAME.key,
            'deviceModel': deviceCommands.MODEL.key
        });
    }
}

【讨论】:

  • 您是否有任何理由删除 $scope?我需要 $watch 对象属性
  • 因为它与我的代码无关,但在您的情况下,您可以简单地通过构造函数提供范围,这没问题,因为基本控制器永远不会在 angularjs 模块上注册。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
相关资源
最近更新 更多