在看完了《JavaScript插件編寫指南》以後,最激動人心的時刻到了!咱們着手開始作一個數據校驗插件吧!javascript
咱們先初始化一個HTML用來做爲校驗的數據來源html
<body>
<div>
<form>
<div>
<label for="exampleInputEmail1">郵箱</label>
<input type="email" id="exampleInputEmail1" placeholder="請輸入合法郵箱">
</div>
<div>
<label for="exampleInputPassword1">手機號碼</label>
<input type="text" id="exampleInputPhone1" placeholder="請輸入合法手機號碼">
</div>
<div>
<label for="exampleInputPassword1">密碼</label>
<input type="password" id="exampleInputPassword1" placeholder="請輸入有效密碼">
</div>
<div>
<label for="exampleInputPassword2">確認密碼</label>
<input type="password" id="exampleInputPassword2" placeholder="請再次輸入密碼">
</div>
<button type="submit">註冊</button>
</form>
</div>
<script src="jquery2.2.4.js"></script>
<script src="dataValidate.js"></script>
</body>
複製代碼
(function(root, factory, plug){
// 工廠函數,用來當即執行下面的function,同時傳入jquery對象和插件名稱
factory($,plug)
// this在非嚴格模式的全局下表明window對象
})(this, function($,plug){
// 測試是否成功調用了工廠函數
console.log(plug);
},"dataValidate")
複製代碼
由於咱們是依賴jQuery
而開發的插件,因此咱們須要把咱們的插件綁定在jQuery
實對象上,即綁定到jQuery
的原型上去。java
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
// 在jQuery中擴展dataValidate方法
$.prototype[plug] = function() {
}
}, "dataValidate")
複製代碼
咱們能夠在HTML上測試jQuery中是否成功綁定了這個屬性jquery
<script> console.log($().dataValidate) </script>
複製代碼
因爲咱們的插件只是針對form
表單中的input
進行校驗,並不會對全部的input
的值進行校驗,因此咱們接下來須要作一個限制:git
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
$.prototype[plug] = function() {
// this 表明的是jquery的實對象
// 若是不在form中,則直接return出去,不進行校驗
if (!this.is("form")) {
return;
}
}
}, "dataValidate")
複製代碼
接下來,咱們知道,咱們須要對input
進行校驗,因此要找到form下面的全部input
,並把它綁定到jQuery的一個屬性上:github
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
$.prototype[plug] = function() {
if (!this.is("form")) {
return;
}
// 將全部input綁定到jquery的$file中
this.$file = this.find("input");
// 對全部的input綁定一個input事件
this.$file.on("input", function() {
// 進行測試
// 在事件函數裏面,this表明觸發這個事件的element對象(即這個this)
// 在構造函數裏,this表明的是這個構造函數的實對象
console.log(this.value)
})
}
}, "dataValidate")
複製代碼
可是這個時候,我有一個問題,這個input
事件確定不能知足全部人的需求,由於這個插件是爲了團隊和用戶開發的,用戶可能須要一個blur
事件來進行觸發,這個時候該怎麼作?npm
==================================解疑======================================== 這個input
事件確定不能寫死,這個時候咱們就須要用到默認配置,將不肯定的因素利用默認配置代替。框架
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
// 存儲默認配置
var DAFAULT = {
initEvent: "input"
}
$.prototype[plug] = function() {
if (!this.is("form")) {
return;
}
this.$file = this.find("input");
// 可是問題又來了,難道就這麼寫DAFAULT.initEvent嗎?
this.$file.on(DAFAULT.initEvent, function() {})
}
}, "dataValidate")
複製代碼
其實咱們也可使用另一種方式,首先我會想個辦法,我會把我默認配置裏面的這些參數和屬性所有擴展到另一個對象上面去------this
,由於this
表明了jQuery
的實對象,我會把這默認配置都擴展到jQuery
的實對象上,誰使用我,我就把這些屬性擴展到誰身上去。函數
那麼,怎麼進行擴展呢? 其實jQuery
已經給咱們準備好了,這個時候就用到了$.extend()
這個方法,這個東西實現其實很簡單,之後有空解讀實現過程,如今大家知道他的用法就好了。測試
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
var DAFAULT = {
initEvent: "input"
}
$.prototype[plug] = function() {
if (!this.is("form")) {
return;
}
this.$file = this.find("input");
$.extend(this, DAFAULT);
// 進行測試
console.log(this.initEvent) // input
this.$file.on(this.initEvent, function() {})
}
}, "dataValidate")
複製代碼
使用了默認配置,可是還有一個問題,用戶怎麼使用他本身的配置呢?
固然是用戶要用什麼,就本身傳什麼。
<script> $("form").dataValidate({ // 用戶怎麼知道initEvent呢? // 那就是經過插件的接口文檔來告訴用戶,這個字段是配置觸發事件的 initEvent: "blur" }) </script>
複製代碼
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
var DAFAULT = {
initEvent: "input"
}
// 接收傳過來的用戶配置參數
$.prototype[plug] = function(options) {
if (!this.is("form")) {
return;
}
this.$file = this.find("input");
// 直接進行擴展
$.extend(this, DAFAULT, options);
// 進行測試
console.log(this.initEvent) // input
this.$file.on(this.initEvent, function() {})
}
}, "dataValidate")
複製代碼
在這個問題解決以後,咱們要開始思考一系列的問題,例如,咱們須要給這個插件提供基礎的默認規則。
數據校驗插件咱們須要提供如下基礎的一些功能:
明白了這些基礎功能以後,咱們就在HTML
裏將規則先補上,
咱們能夠經過配置自定義屬性(data-
)(也叫作指令)的方式來進行配置:
可是咱們要清楚哪些是咱們的配置,哪些是這個標籤擴展的自定義屬性,若是都是以data
開頭,那就沒法區分是配置仍是擴展的自定義屬性,因此這個時候要加個標籤來代表這是個人插件配置dv
,因此在接口文檔裏面,也要告訴用戶經過data-dv
來進行配置
<form>
<div>
<label for="exampleInputEmail1">郵箱</label>
<!-- 不能爲空 郵箱正則 -->
<input type="email" id="exampleInputEmail1" placeholder="請輸入合法郵箱" data-dv-required=true data-dv-required-message="郵箱不能爲空" data-dv-reg="^\w+@\w+\.\w+$" data-dv-reg-message="郵箱格式不正確">
</div>
<div>
<label for="exampleInputPassword1">手機號碼</label>
<!-- 不能爲空 手機號正則 -->
<input type="text" id="exampleInputPassword1" placeholder="請輸入合法手機號碼" data-dv-required=true data-dv-required-message="手機號碼不能爲空" data-dv-reg="^1\d{10}$" data-dv-reg-message="手機號碼格式不正確">
</div>
<div>
<label for="exampleInputPassword1">密碼</label>
<!-- 不能爲空 密碼正則 字符長度 -->
<input type="password" id="exampleInputPassword1" placeholder="請輸入有效密碼" data-dv-required=true data-dv-required-message="密碼不能爲空" data-dv-reg="^\w+$" data-dv-reg-message="密碼格式不正確" data-dv-min-length=6 data-dv-min-length-message="密碼長度不正確">
</div>
<div>
<label for="exampleInputPassword1">確認密碼</label>
<!-- 不能爲空 密碼一致 -->
<input type="password" id="exampleInputPassword1" placeholder="請再次輸入密碼" data-dv-required=true data-dv-required-message="密碼不能爲空" data-dv-confirm=true data-dv-confirm-message="兩次密碼不一致">
</div>
</form>
複製代碼
配置完了以後,你會發現,咱們配置的這些玩意好像並無什麼用,因此下面咱們就須要根據頁面上的配置在js裏面來寫相應的默認規則。
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
var DAFAULT = {
initEvent: "input"
}
// 默認規則
var RULES = {
"reg": function() {},
"required": function() {},
"min-length": function() {},
"confirm": function() {}
}
// 接收傳過來的用戶配置參數
$.prototype[plug] = function(options) {
if (!this.is("form")) {
return;
}
this.$file = this.find("input");
$.extend(this, DAFAULT, options);
this.$file.on(this.initEvent, function() {
// 遍歷默認配置
$.each(RULES, function(key, fn) {
// 這個時候this指的是element對象
// 咱們想用this.data來獲取data上面用戶自定義的屬性,可是這個方法只有jQuery對象才擁有,這個時候該怎麼辦?
});
})
}
}, "dataValidate")
複製代碼
其實很簡單,包裝一下就能夠了,將element
對象包裝成jQuery
對象。
(function(root, factory, plug) {
factory($, plug)
})(this, function($, plug) {
var DAFAULT = {
initEvent: "input",
plugName: "dv"
}
// 默認規則
var RULES = {
"reg": function() {},
"required": function() {},
"min-length": function() {},
"confirm": function() {}
}
// 接收傳過來的用戶配置參數
$.prototype[plug] = function(options) {
if (!this.is("form")) {
return;
}
this.$file = this.find("input");
$.extend(this, DAFAULT, options);
this.$file.on(this.initEvent, function() {
// 包裝
var _this = $(this);
$.each(RULES, function(key, fn) {
// _this.data("dv-" + key) 這樣作有點傻,因此在默認配置裏,寫上dv
var $fileName = _this.data(this.plugName + "-" + key);
var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
// 測試一下輸出的內容
console.log($fileName);
console.log($fileMessage);
});
})
}
}, "dataValidate")
複製代碼
接下來咱們須要用到call
來調用函數,而且改變this
指向
作個測試:
var RULES = {
"reg": function() {
console.log(this);
},
"required": function() {
console.log(this);
},
"min-length": function() {
console.log(this);
},
"confirm": function() {
console.log(this);
}
}
複製代碼
$.each(RULES, function(key, fn) {
var $fileName = _this.data(this.plugName + "-" + key);
var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
if ($fileName) {
// fn.call()
// fn.call(this)
fn.call(_this)
}
});
複製代碼
看明白了this
的指向以後,咱們就要開始着手完成默認的校驗規則
var RULES = {
"reg": function(data) {
return new RegExp(data).test(this.val());
},
"required": function(data) {
return this.val();
},
"min-length": function(data) {
return this.val().length > data;
},
"confirm": function(data) {
// 思考一下密碼一致的校驗該怎麼作?
}
}
複製代碼
$.each(RULES, function(key, fn) {
var $fileName = _this.data(this.plugName + "-" + key);
var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
if ($fileName) {
var result = fn.call(_this, $fileName);
if (!result) {
// 進行報錯處理
}
}
});
複製代碼
校驗是否一致能夠這樣作:
"confirm": function(data) {
var passwordElement = $(":password")[0];
if (passwordElement.value == "" || this.val() != passwordElement.value) {
return false;
} else {
return true;
}
}
複製代碼
this.$file.on(this.initEvent, function() {
var _this = $(this);
// 監測是否已經有報錯信息,若是有,就全乾掉
_this.siblings('p').remove();
$.each(RULES, function(key, fn) {
var $fileName = _this.data(this.plugName + "-" + key);
var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
if ($fileName) {
var result = fn.call(_this, $fileName);
if (!result) {
// 直接在後面追加報錯信息
_this.after("<p style='color:red'>" + $fileMessage + "</p>")
}
}
});
})
複製代碼
到了這一步基本上完成了,用戶只須要引入咱們這個js文件,而後把接口文檔交給用戶,讓用戶自定義報錯信息和正則校驗就能夠了。
可是,若是用戶想要擴展本身的默認方法,即擴展默認校驗規則,好比新增一個max-length
,這個時候該怎麼辦?
按照咱們的這種方式,大家以爲可以進行擴展嗎?
固然能夠,由於咱們的方法綁定在jQuery
實對象上面,因此就可使用jQuery
的擴展方法的方式進行擴展,而且要告訴用戶用這種方式進行擴展
$.fn.dataValidate.extendValidate = function(options) {
$.extend(RULES, options)
}
複製代碼
<script type="text/javascript"> // 用戶擴展 $.fn.dataValidate.extendValidate({ "max-length": function(data) { return this.val().length <= data; } }) </script>
複製代碼
咱們能夠配置data-dv-max-length
來進行測試。
至此,一個簡單的數據校驗插件已經開發完成。
咱們開發一個需求或者解決一個問題以前,多想一想該如何改纔會使代碼複用性更高,效率更快,而不是一上手就不假思索的用if{}else{}
來進行判斷修改,這樣代碼量多了以後,維護起來就很麻煩了。
而咱們這種形式的代碼,進行數據校驗總比每次校驗都使用if{}else{}
的代碼好上千百倍,可維護性,可擴展性都比較好,固然這種代碼也不是一朝一夕就能寫出來的,須要日積月累。
最後,你們一塊兒加油吧。
最後很差意思推廣一下我基於 Taro
框架寫的組件庫:MP-ColorUI。
能夠順手 star 一下我就很開心啦,謝謝你們。