項目總結 關於layui使用上的坑

  • 感悟源頭

最近kk在作一個小型的功能業務平臺,但因爲客戶對瀏覽器兼容性的要求比較強(兼容IE低版本),從技術選型上也須要配合後臺研發進行。因此最後採用了一套偏後端人員開發的方案:javascript

  • 功能組件:layui
    • 模板引擎:laytpl
    • UI組件:layui.element、layui.laydate(日曆)
  • 響應式佈局:Boostrap
    • 表單驗證:Boostrap Validator
  • 後端開發:GUNS(一個利於快速搭建業務平臺的框架)

與此同時,還包括有脫離項目頁面的:html

  • EDM郵件信
  • 下載報告:html形式存儲本地瀏覽

雖然說這些技術棧確實是kk初學前端時就接觸過的,但layui着實在開發過程當中坑了kk一把,因此在這裏想作個總結。前端

不過這個項目也不是那麼沒突破,藉此機會,kk確實仍是接觸了一把郵件信的編寫,屬於HTML基礎上的一次突破,也算是一次很好的經驗借鑑。java

事不宜遲,我們開始。ajax

  • 開發工具類方法

  • 1. Boostrap Validator的方法封裝

var Feng = {
        initValidator: function (formId, fields) {
        $('#' + formId).bootstrapValidator({
            feedbackIcons: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: fields,
            live: 'enabled',
            message: '該字段不能爲空'
            });
        }
    };
複製代碼

該方法封裝在了工具類Feng裏,可供業務頁面全局調用。json

//設置validator校驗規則
var validateFields = {
    time: {
        trigger:"change input click", //監聽change動做
        validators: {
            notEmpty: {
                message: '執行時間不能爲空'
            }
        }
    },
    caption: {
        validators: {
            notEmpty: {
                message: '任務名稱不能爲空'
            }
        }
    }
};
//業務頁面內初始化就調用Feng工具類
$(function () {
    Feng.initValidator("taskInfoForm", validateFields);
});

//點擊提交觸發表單校驗,驗證數據是否爲空
UserInfoDlg.validate = function () {
    $('#userInfoForm').data('bootstrapValidator').validate();//手動對錶單進行校檢
    $('#taskInfoForm').data('bootstrapValidator').validate();//手動對錶單進行校檢
    return $('#userInfoForm').data('bootstrapValidator').isValid() && $('#taskInfoForm').data('bootstrapValidator').isValid();
};
複製代碼
  • 2. 基於JQ手動封裝ajax方法

(function () {
    var $ax = function (url, success, error) {
        this.url = url;
        this.type = "post";
        this.data = {};
        this.dataType = "json";
        this.async = false;
        this.success = success;
        this.error = error;
    };

    $ax.prototype = {
        start: function () {
            var _this = this;

            if (this.url.indexOf("?") == -1) {
                this.url = this.url + "?jstime=" + new Date().getTime();
            } else {
                this.url = this.url + "&jstime=" + new Date().getTime();
            }
            jQuery.ajax({
                url: this.url,
                type: this.type,
                dataType: this.dataType,
                async: this.async,
                data: this.data,
                success: function (e) {
                    _this.success(e);
                },
                error: function (data) {
                    _this.error(data);
                }
            });
        },

        set: function (key, value) {
            if (typeof key == "object") {
                for (var i in key) {
                    if (typeof i == "function")
                        continue;
                    this.data[i] = key[i];
                }
            } else {
                this.data[key] = (typeof value == "undefined") ? $("#" + key).val() : value;
            }
            return this;
        },

        setData: function (data) {
            this.data = data;
            return this;
        },

        clear: function () {
            this.data = {};
            return this;
        }
    };

    window.$ax = $ax;

}());
複製代碼

業務頁面調用$ax:bootstrap

//提交信息
    var ajax = new $ax(Feng.ctxPath + "/task/add", function (data) {//傳入ajax成功(success)後的callback方法
        Feng.success("添加成功!");
        if (window.parent.MgrUser != undefined) {
            window.parent.MgrUser.table.refresh();
            UserInfoDlg.close();
        }
        window.location.reload();
    }, function (data) {//傳入ajax失敗(error)後的callback方法
        Feng.error("添加失敗!" + data.responseJSON.message + "!");
    });
    ajax.set(this.userInfoData);//設置提交的表單信息,$ax對象根據輸入data的類型放進this.data中
    ajax.start();//發出ajax請求
複製代碼
  • 3. 表單取值

該方法根據輸入的表單名name,或是class,判斷該表單輸入哪一種類型(radio、checkbox、日曆、普通輸入框),進行不一樣方式的取值和輕量校驗。後端

/** * 設置對話框中的數據 * * @param key 數據的名稱 * @param val 數據的具體值 */
UserInfoDlg.set = function (key, value) {
    if (typeof value == "undefined") {
        if (key == 'time') {
            var value = $("#" + key).val();
            var startTime = value.substring(0, value.indexOf("-")).replace(/(\w*)年(.*)月(.*)日(.*)/g, "$1-$2-$3").replace(/\s*/g, "");
            var endTime = value.substring(value.indexOf("-") + 1).replace(/(\w*)年(.*)月(.*)日(.*)/g, "$1-$2-$3").replace(/\s*/g, "");
            console.log(startTime);
            console.log(endTime);
            this.userInfoData['startTime'] = startTime;
            this.userInfoData['endTime'] = endTime;
            return this;
        }
        if (typeof $("#" + key).val() == "undefined") {
            var str = "";
            var ids = "";
            $("input[name='" + key + "']:checkbox").each(function () {
                if (true == $(this).is(':checked')) {
                    str += $(this).val() + ",";
                }
            });
            if (str && key != 'time') {
                if (str.substr(str.length - 1) == ',') {
                    ids = str.substr(0, str.length - 1);
                }
            } else {
                $("input[name='" + key + "']:radio").each(function () {
                    if (true == $(this).is(':checked')) {
                        ids = $(this).val()
                    }
                });
            }
            this.userInfoData[key] = ids;
        } else {
            this.userInfoData[key] = $("#" + key).val();
        }
    }

    return this;
};
複製代碼

業務頁面調用: 使用JQ鏈式調用,將表單全部項目的name推入便可瀏覽器

/** * 收集數據 */
UserInfoDlg.collectData = function () {
    this.set('orgName').set('orgCode').set('orgContactPerson').set('orgContactMobile').set('caption')
        .set('url').set('time').set('period').set('importance').set('smsList').set('emailList').set('depth');
};
複製代碼
  • 坑1:日曆組件和表單驗證

  • 1. 業務場景

如上圖爲一個添加了Boostrap Validator表單驗證的雙日曆(layui.laydate)輸入框,表單提交前須要對其輸入的內容進行非空校驗。
框架

  • 2. 技術實現

其結構組成代碼以下:

<!-- 傳入jQuery文件-->
    
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->

    <!--引入BoostrapValidator-->
    
    <!--引入laydate -->
  
    <div class="form-horizontal">
        <div class="row form-row">
            <div class="col-sm-12 form-group">
                <div class="form-group" style="">
                    <label class="col-sm-2 control-label">
                        <span style="color:red;">*</span>執行時間:
                    </label>
                    <div class="col-sm-5">
                        <input class="form-control" placeholder="請選擇開始日期 ~ 結束日期" id="time" name="time" value="" type="text">
                    </div>
                </div>
            </div>
        </div>
    </div>
複製代碼

laydate組件配置代碼:

laydate.render({
        elem: '#time'
        , range: true //或 range: '~' 來自定義分割字符
        , format: 'yyyy年MM月dd日' //可任意組合
        , done: function (value, date) {
            $("#time").change();
            setTimeout(function () {
              $('#taskInfoForm')
              .data('bootstrapValidator')
                    .updateStatus('time','NOT_VALIDATED', null)
                    .validateField('time');
            }, 200)
        }
    });
    //直接監聽日曆輸入框的blur事件
    $("#time").blur(function () {
        setTimeout(function () {
            $('#taskInfoForm').data('bootstrapValidator')
                .updateStatus('time', 'NOT_VALIDATED', null)
                .validateField('time');
        }, 200)
    });
複製代碼
  • 3. 掉進的坑

Boostrap Validator對第三方js輸入表單的信息,沒法自動觸發校驗。

實如今業務場景中,就是當laydate雙日曆選定日期事後,點擊提交觸發校驗,仍然視爲輸入框爲空。

  • 4.解決方案

第一步,在日曆輸入框所對應的校驗規則validatorField裏添加:

trigger:"change input click", 
複製代碼

即input的這些事件皆可自動觸發validate()。

done: function (value, date) {
            $("#time").change();
              $('#taskInfoForm')
              .data('bootstrapValidator')
                    .updateStatus('time','NOT_VALIDATED', null)
                    .validateField('time');
        }
複製代碼

第二步:在laydate完成done事件後觸發input的change事件並手動觸發校驗一次。

結果:能夠實現日曆值變化時候的表單從新校驗。

這下新問題出現了:

在輸入框從空值到有值的過程當中,仍然沒法觸發校驗

  • 5.根本緣由

kk探究了下各路大神的文章,發現其問題根本在於:

laydate 加載日期賦值給 input 在 bootstrapValidator 驗證以後,因此在點擊時間插件以後進行二次特定字段驗證便可 取自文章:bootstrapValidator 驗證框架與 layui 時間插件兼容

  • 6.優化解決方案

1.完善laydate的done回調事件,對validate二次校驗設置時間延遲(200ms基本不影響體驗)

done: function (value, date) {
            $("#time").change();
            setTimeout(function () {
              $('#taskInfoForm')
              .data('bootstrapValidator')
                    .updateStatus('time','NOT_VALIDATED', null)
                    .validateField('time');
            }, 200)
        }
複製代碼

2.附加的,也能夠完善日曆輸入框自己的blur事件,將validate綁定在blur事件上

$("#time").blur(function () {
        setTimeout(function () {
            $('#taskInfoForm').data('bootstrapValidator')
                .updateStatus('time', 'NOT_VALIDATED', null)
                .validateField('time');
        }, 200)
    });
複製代碼

結果:可完整解決當前問題,輸入日曆可正常觸發二次校驗。

  • 坑2:模板引擎與UI組件

  • 1.掉進的坑

    laytpl與layui.element不可共用

  • 2.業務場景

    kk想嘗試在頁面中引用laytpl的麪包屑功能,須要導入element的功能組件。

但kk發現其與寫在laytpl裏的DOM結構代碼沒法兼容,即laytpl渲染出的結構沒法正常使用layui自帶的UI組件,或者說已經加載了其DOM結構及樣式,但未從layui裏初始化其功能邏輯。

  • 3.解決方案

    最終採用了手動重構功能邏輯的方法。

如上內容屬於kk我的意見,若有更好的解決方案,或內容有錯誤遺漏,歡迎指正!

相關文章
相關標籤/搜索