2

我想知道用 javascript 编写复杂表单的最有效、安全和智能的方法。

通常一个用户表单可能非常复杂,有很多不同的状态、复杂的检查等等,要做好工作,一个好的概念是绝对必要的。

我真的相信最好的解决方案是状态机。

以下代码是我为使用 RFID 标签密钥进行用户注册所做的表单核心逻辑,其中用户可以使用不同的凭据(例如电话、密钥 RFID 标签、邮件)注册自己,并在稍后阶段在同一个论坛完成注册。只考虑它背后的高层次逻辑。

迭代可能的转换的主循环(按优先级顺序):

/* Evaluate the actual form state (status) and check if it's possible to change
 * to another status with a greater priority.
 * If the state transition conditions are verified the transition callback is executed
 * which, in case the state doesn't, is an empty function.
 */
setNextFormStatus: function(field) {

    var sts,
    that =  this;

    function conditionsAreValid(sts) {
        var context = that.statusToConditionsMap[sts];

        return ( sts == 'new_account' || that[context.field].state == context.state );
    }

    for (sts in this.statusToConditionsMap[this.status.actual].changes) {
        var transition = this.statusToConditionsMap[this.status.actual].changes[sts];

        if (transition && conditionsAreValid(sts)) {
            if (sts != this.status.actual) {
                this.status.previous = this.status.actual;
                this.status.actual = sts;
                this._resetForm(); // simple reset function
                transition.apply(this);
            }
            break;
        }
    }
}

当状态按优先级顺序列出时,所有状态、它们的转换条件和它们的转换回调都在字典中定义:

/* 
 * This is the dictionary which defines form status states machine
 * 
 * For each status are defined the following attributes:
 *     · state & field: define the condition to enter this status. The field must have that state (i.e. field.state == state)
 *     · changes (optional): the list of possible next status from this one, ordered by priority. Each status has an handle to call
 */
this.statusToConditionsMap = {
    'registered_key':{
        state: 'registered',
        field: 'key'
    },
    'processed_key_with_username':{
        state: 'unlinked',
        field: 'key',
        changes: {
            'processed_key_with_username': function() {}, // empty cause callback is unnecessary 
            'new_account': this._checkNotEmptyFields
        }
    },
    'phone_already_present_confirmed':{
        state: 'already_present_confirmed',
        field: 'phone',
        changes: {
            'phone_already_present_confirmed': function() {},
            'phone_already_present_unconfirmed': this.phone_already_present_unconf_data_filler,
            'new_account': this._checkNotEmptyFields
        }
    },
    'phone_already_present_unconfirmed':{
        state: 'already_present_unconfirmed',
        field: 'phone',
        changes: {
            'phone_already_present_confirmed': this.phone_already_present_data_filler,
            'phone_already_present_unconfirmed': function() {},
            'new_account': this._checkNotEmptyFields
        }
    },
    'email_already_present':{
        state: 'email_already_present',
        field: 'email',
        changes: {
            'phone_already_present_confirmed': this.phone_already_present_data_filler,
            'phone_already_present_unconfirmed': this.phone_already_present_unconf_data_filler,
            'email_already_present': function() {},
            'new_account': this._checkNotEmptyFields
        }
    },
    'new_account':{
        state:'',
        field: '',
        changes: {
            'registered_key': this.registered_key_data_filler,
            'processed_key_with_username': this.processed_desikey_data_filler,
            'phone_already_present_confirmed': this.phone_already_present_data_filler,
            'phone_already_present_unconfirmed': this.phone_already_present_unconf_data_filler,
            'email_already_present': function() {this.showMailCheckbox(); this.runCheck('phone');},
            'new_account': function() {}
        }
    }
}

哪个是实现复杂表单的最佳实践?

任何其他解决方案或方法将不胜感激。

4

0 回答 0