JS常見的API擴展形式(prototype、jquery、vue插件封裝)以及怎樣設計出易擴展的表單驗證功能?


常見的API擴展形式

prototype

比如我現在有一個需求,給定一個字符串,給方法傳遞一個參數為數字類型來確定當前字符串重復次數,例如:

'abc'.repeatStringNumTimes(3) // abcabcabc

如果按照一般的思維就是我們把這個方法綁定到String的原型上,如下代碼:

String.prototype.repeatStringNumTimes = String.prototype.repeatStringNumTimes || function(times) {
    var str = '';
    for(var i = 0; i < times; i++) {
        str += this;
    }
    return str;
}

 jQuery

根據《jQuery高級編程》的描述,jQuery插件開發方式主要有三種:

  • 通過$.extend()來擴展jQuery

  • 通過$.fn 向jQuery添加新的方法

  • 通過$.widget()應用jQuery UI的部件工廠方式創建

通常我們使用第二種方法來進行簡單插件開發,說簡單是相對於第三種方式。第三種方式是用來開發更高級jQuery部件的,該模式開發出來的部件帶有很多jQuery內建的特性,比如插件的狀態信息自動保存,各種關於插件的常用方法等,非常貼心,這里不細說。

而第一種方式又太簡單,僅僅是在jQuery命名空間或者理解成jQuery身上添加了一個靜態方法而以。所以我們調用通過.extend().extend()添加的函數時直接通過符號調用($.myfunction())而不需要選中DOM元素($('#example').myfunction())。請看下面的例子。

$.extend({
    sayHello: function(name) {
        console.log('Hello,' + (name ? name : 'Dude') + '!');
    }
})
$.sayHello(); //調用
$.sayHello('Wayou'); //帶參調用

看一個jquery封裝的面向對象的插件開發代碼:

//定義Beautifier的構造函數
var Beautifier = function(ele, opt) {
    this.$element = ele,
    this.defaults = {
        'color': 'red',
        'fontSize': '12px',
        'textDecoration':'none'
    },
    this.options = $.extend({}, this.defaults, opt)
}
//定義Beautifier的方法
Beautifier.prototype = {
    beautify: function() {
        return this.$element.css({
            'color': this.options.color,
            'fontSize': this.options.fontSize,
            'textDecoration': this.options.textDecoration
        });
    }
}
//在插件中使用Beautifier對象
$.fn.myPlugin = function(options) {
    //創建Beautifier的實體
    var beautifier = new Beautifier(this, options);
    //調用其方法
    return beautifier.beautify();
}

調用方式:

$(function() {
    $('a').myPlugin({
        'color': '#2C9929',
        'fontSize': '20px'
    });
})

 感興趣的可以詳細查看文章:《jQuery插件開發進階》

 vue

插件通常會為 Vue 添加全局功能。插件的范圍沒有限制——一般有下面幾種:

  • 1.添加全局方法或者屬性,如: vue-custom-element
  • 2.添加全局資源:指令/過濾器/過渡等,如 vue-touch
  • 3.通過全局 mixin 方法添加一些組件選項,如: vue-router
  • 4.添加 Vue 實例方法,通過把它們添加到 Vue.prototype 上實現。
  • 5.一個庫,提供自己的 API,同時提供上面提到的一個或多個功能,如 vue-router

Vue.js 的插件應當有一個公開方法 install 。這個方法的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象:

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或屬性
  Vue.myGlobalMethod = function () {
    // 邏輯...
  }

  // 2. 添加全局資源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 邏輯...
    }
    ...
  })

  // 3. 注入組件
  Vue.mixin({
    created: function () {
      // 邏輯...
    }
    ...
  })

  // 4. 添加實例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 邏輯...
  }
}
export default MyPlugin

封裝的插件怎樣使用?通過全局方法 Vue.use() 使用插件:

// 調用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)

 也可以傳入一個選項對象:

Vue.use(MyPlugin, { someOption: true })

 實現一個表單驗證

設計表單驗證的規則就是開放-封閉驗證,使用策略模式封裝。

一般方案

我們先寫一個html代碼片段好驗證代碼:

<form action="" id="registerForm" method="post" onsubmit="return submitValidate()">
<p>
    <label>請輸入用戶名:</label>
    <input type="text" name="userName" />
</p>
<p>
    <label>請輸入密碼:</label>
    <input type="text" name="password" />
</p>
<p>
    <label>請輸入手機號碼:</label>
    <input type="text" name="phoneNumber" />
</p>
<div>
    <button type="submit">提交</button>
</div>
</form>

在form上綁定的submit,想實現的submitValidate方法代碼如下:

function submitValidate() {
    var registerForm = document.getElementById("registerForm");
    var rulesArr = [
        {
            el: registerForm.userName.value,
            rules: [{rule: 'isNonEmpty',message: '用戶名不能為空'},{rule:'minLength:3',message: '用戶名長度不能小於3位'}]
        },
        {
            el: registerForm.password.value,
            rules: [{rule: 'isNonEmpty',message: '密碼不能為空'},{rule:'minLength:6',message: '密碼的長度不能小於6位'}]
        },
        {
            el: registerForm.phoneNumber.value,
            rules: [{rule: 'isNonEmpty',message: '手機號不能為空'},{rule:'isMobile',message: '手機號碼格式不正確'}]
        }
    ]
    var resultMsg = validate.check(rulesArr);
    if(resultMsg) {
        alert(resultMsg);
        return false;
    }
    return true;
}

下面我們編寫validate驗證方法,代碼如下:

var validate = (function() {
    // 校驗規則的各種算法
    var rules = {
        // 判斷非空
        isNonEmpty: function(value,errorMsg) {
            if(!value) {
                return errorMsg;
            }
        },
        // 判斷最小長度
        minLength: function(value,length,errorMsg) {
            if(value.toString().length < length) {
                return errorMsg;
            }
        },
        // 判斷最大長度
        maxLength: function(value,length,errorMsg) {
            if(value.toString().length > length) {
                return errorMsg;
            }
        },
        // 判斷手機號
        isMobile: function(value,errorMsg) {
            if (!/(^1[0-9]{10}$)/.test(value)) {
                return errorMsg;
            }
        },
        // 判斷座機電話
        isTel: function(value,errorMsg) {
            if(!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
                return errorMsg;
            }
        }
    }
    
    
    return {
        /** 校驗方法
         * @param {Array} arr
         * @return {*}
         * */
        check: function(arr) {
            var ruleMsg;
            var checkRule;
            var _rule;
            for(var i = 0, len = arr.length; i < len; i++) {
                // 沒有當前校驗字段
                if(arr[i].el === undefined) {
                    return '沒有當前字段'
                }
                for(var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
                    var ruleObj = arr[i].rules[j];
                    checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                    _rule = checkRule.shift(); // 獲取校驗算法名稱
                    checkRule.unshift(arr[i].el); // checkRule首位存入校驗的value值
                    checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                    ruleMsg = rules[_rule].apply(null,checkRule);
                    if(ruleMsg) {
                        return  ruleMsg;
                    }
                }
            }
        }
    }    
})();

以上代碼就是常規實現的表單驗證,看似也夠用了,但是如果一個系統中有多個表單提交驗證,並且有部分驗證方式不是那么通用,我們不可能再去修改代碼中的rules,那樣這個rules校驗的算法越來越多,並且很多不是很通用的,那么我們怎樣來解決呢?

在驗證函數中增加一個添加規則算法的方法,代碼如下:

var validate = (function() {
    // 校驗規則的各種算法
    var rules = {
        // 判斷非空
        isNonEmpty: function(value,errorMsg) {
            if(!value) {
                return errorMsg;
            }
        },
        // 判斷最小長度
        minLength: function(value,length,errorMsg) {
            if(value.toString().length < length) {
                return errorMsg;
            }
        },
        // 判斷最大長度
        maxLength: function(value,length,errorMsg) {
            if(value.toString().length > length) {
                return errorMsg;
            }
        },
        // 判斷手機號
        isMobile: function(value,errorMsg) {
            if (!/(^1[0-9]{10}$)/.test(value)) {
                return errorMsg;
            }
        },
        // 判斷座機電話
        isTel: function(value,errorMsg) {
            if(!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
                return errorMsg;
            }
        }
    }
    
    
    return {
        /** 校驗方法
         * @param {Array} arr
         * @return {*}
         * */
        check: function(arr) {
            var ruleMsg;
            var checkRule;
            var _rule;
            for(var i = 0, len = arr.length; i < len; i++) {
                // 沒有當前校驗字段
                if(arr[i].el === undefined) {
                    return '沒有當前字段'
                }
                for(var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
                    var ruleObj = arr[i].rules[j];
                    checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                    _rule = checkRule.shift(); // 獲取校驗算法名稱
                    checkRule.unshift(arr[i].el); // checkRule首位存入校驗的value值
                    checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                    ruleMsg = rules[_rule].apply(null,checkRule);
                    if(ruleMsg) {
                        return  ruleMsg;
                    }
                }
            }
        },
        
        // 添加規則
        addRule: function(ruleName,fn) {
            rules[ruleName] = fn;
        }
    }    
})();

比如用戶名只能是字母跟數字的組合,那么我們就添加一個規則,代碼如下:

validate.addRule('isAlphaNum', function(value, errorMsg) {
    if (/[^a-zA-Z0-9]/.test(value)) {
        return errorMsg;
    }
})

submitValidate方法的代碼修改為如下:

function submitValidate() {
    var registerForm = document.getElementById("registerForm");
    validate.addRule('isAlphaNum', function(value, errorMsg) {
        if (/[^a-zA-Z0-9]/.test(value)) {
            return errorMsg;
        }
    })
    var rulesArr = [{
            el: registerForm.userName.value,
            rules: [{
                rule: 'isNonEmpty',
                message: '用戶名不能為空'
            }, {
                rule: 'minLength:3',
                message: '用戶名長度不能小於3位'
            }, {
                rule: 'isAlphaNum',
                message: '用戶名只能是數字跟字母的組合'
            }]
        },
        {
            el: registerForm.password.value,
            rules: [{
                rule: 'isNonEmpty',
                message: '密碼不能為空'
            }, {
                rule: 'minLength:6',
                message: '密碼的長度不能小於6位'
            }]
        },
        {
            el: registerForm.phoneNumber.value,
            rules: [{
                rule: 'isNonEmpty',
                message: '手機號不能為空'
            }, {
                rule: 'isMobile',
                message: '手機號碼格式不正確'
            }]
        }
    ]
    var resultMsg = validate.check(rulesArr);
    if (resultMsg) {
        alert(resultMsg);
        return false;
    }
    return true;
}

 運行效果如圖所示:

升級方案

 如果我們想實現如圖這樣的驗證結果:

那么我們就需要保存所有元素的錯誤信息,那么我們新添加一個checkAll的方法,代碼如下:

var validate = (function() {
    // 校驗規則的各種算法
    var rules = {
        // 判斷非空
        isNonEmpty: function(value, errorMsg) {
            if (!value) {
                return errorMsg;
            }
        },
        // 判斷最小長度
        minLength: function(value, length, errorMsg) {
            if (value.toString().length < length) {
                return errorMsg;
            }
        },
        // 判斷最大長度
        maxLength: function(value, length, errorMsg) {
            if (value.toString().length > length) {
                return errorMsg;
            }
        },
        // 判斷手機號
        isMobile: function(value, errorMsg) {
            if (!/(^1[0-9]{10}$)/.test(value)) {
                return errorMsg;
            }
        },
        // 判斷座機電話
        isTel: function(value, errorMsg) {
            if (!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
                return errorMsg;
            }
        }
    }


    return {
        /** 校驗方法
         * @param {Array} arr
         * @return {*}
         * */
        check: function(arr) {
            var ruleMsg;
            var checkRule;
            var _rule;
            for (var i = 0, len = arr.length; i < len; i++) {
                // 沒有當前校驗字段
                if (arr[i].el === undefined) {
                    return '沒有當前字段'
                }
                for (var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
                    var ruleObj = arr[i].rules[j];
                    checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                    _rule = checkRule.shift(); // 獲取校驗算法名稱
                    checkRule.unshift(arr[i].el); // checkRule首位存入校驗的value值
                    checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                    ruleMsg = rules[_rule].apply(null, checkRule);
                    if (ruleMsg) {
                        return ruleMsg;
                    }
                }
            }
        },
        
        // 校驗所有接口
        checkAll: function(arr) {
            var ruleMsg;
            var checkRule;
            var _rule;
            var reusltMsg = [];
            for (var i = 0, len = arr.length; i < len; i++) {
                // 沒有當前校驗字段
                if (arr[i].el === undefined) {
                    return '沒有當前字段'
                }
                for (var j = 0, ruleLen = arr[i].rules.length; j < ruleLen; j++) {
                    var ruleObj = arr[i].rules[j];
                    checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                    _rule = checkRule.shift(); // 獲取校驗算法名稱
                    checkRule.unshift(arr[i].el); // checkRule首位存入校驗的value值
                    checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                    ruleMsg = rules[_rule].apply(null, checkRule);
                    if (ruleMsg) {
                        reusltMsg.push({
                            el: arr[i].el,
                            rules: _rule,
                            message: ruleMsg,
                            alias: arr[i].alias   // 綁定一個別名用處:綁定到具體的一個DOM元素上顯示錯誤信息
                        })
                        break; // 跳出當前循環,不用把當前一個元素上多個驗證不通過結果都存儲起來
                    }
                }
            }
            return reusltMsg.length > 0 ? reusltMsg : false;
        },

        // 添加規則
        addRule: function(ruleName, fn) {
            rules[ruleName] = fn;
        }
    }
})();

我們調整下html代碼:

<form action="" id="registerForm" method="post" onsubmit="return submitValidate()">
    <p>
        <label>請輸入用戶名:</label>
        <input type="text" name="userName" />
        <span class="error"></span>
    </p>
    <p>
        <label>請輸入密碼:</label>
        <input type="text" name="password" />
        <span class="error"></span>
    </p>
    <p>
        <label>請輸入手機號碼:</label>
        <input type="text" name="phoneNumber" />
        <span class="error"></span>
    </p>
    <div>
        <button type="submit">提交</button>
    </div>
</form>

css樣式:

<style>
    .error {
        color: red;
    }
</style>

submitValidate方法的代碼調整為:

function submitValidate() {
    var registerForm = document.getElementById("registerForm");
    validate.addRule('isAlphaNum', function(value, errorMsg) {
        if (/[^a-zA-Z0-9]/.test(value)) {
            return errorMsg;
        }
    })
    var rulesArr = [{
            el: registerForm.userName.value,
            alias: 'userName',
            rules: [{
                rule: 'isNonEmpty',
                message: '用戶名不能為空'
            }, {
                rule: 'minLength:3',
                message: '用戶名長度不能小於3位'
            }, {
                rule: 'isAlphaNum',
                message: '用戶名只能是數字跟字母的組合'
            }]
        },
        {
            el: registerForm.password.value,
            alias: 'password',
            rules: [{
                rule: 'isNonEmpty',
                message: '密碼不能為空'
            }, {
                rule: 'minLength:6',
                message: '密碼的長度不能小於6位'
            }]
        },
        {
            el: registerForm.phoneNumber.value,
            alias: 'phoneNumber',
            rules: [{
                rule: 'isNonEmpty',
                message: '手機號不能為空'
            }, {
                rule: 'isMobile',
                message: '手機號碼格式不正確'
            }]
        }
    ]
    var resultMsg = validate.checkAll(rulesArr);
    if (resultMsg) {
        for(var re = 0, len = resultMsg.length; re < len; re++) {
            var curResult = resultMsg[re];
            var errorDom = document.querySelector('#registerForm p [name="'+curResult.alias+'"]').nextElementSibling;
            errorDom.innerHTML = curResult.message;
        }
        
        return false;
    }
    return true;
}

 這樣得到的結果就是我們剛才截圖的結果了。

兼容失去焦點的方案

如果想兼容失去焦點也觸發后面的錯誤信息提示,暫寫了一個草稿代碼如下:

var validate = (function() {
    // 校驗規則的各種算法
    var rules = {
        // 判斷非空
        isNonEmpty: function(value, errorMsg) {
            if (!value) {
                return errorMsg;
            }
        },
        // 判斷最小長度
        minLength: function(value, length, errorMsg) {
            if (value.toString().length < length) {
                return errorMsg;
            }
        },
        // 判斷最大長度
        maxLength: function(value, length, errorMsg) {
            if (value.toString().length > length) {
                return errorMsg;
            }
        },
        // 判斷手機號
        isMobile: function(value, errorMsg) {
            if (!/(^1[0-9]{10}$)/.test(value)) {
                return errorMsg;
            }
        },
        // 判斷座機電話
        isTel: function(value, errorMsg) {
            if (!/^\d{3}-d{8}|d{4}-d{7}|d{11}$/.test(value)) {
                return errorMsg;
            }
        }
    }


    return {
        /** 校驗方法
         * @param {Object} vertifyObj 驗證結構如:{userName:[{rule: 'isNonEmpty',message: '用戶名不能為空'},{rule: 'minLength:3',message: '用戶名長度不能小於3位'}}
         * @param {Array} arr
         * @return {*}
         * */
        check: function(vertifyObj,arr) {
            var ruleMsg;
            var checkRule;
            var _rule;
            for (var i = 0, len = arr.length; i < len; i++) {
                // 沒有當前校驗字段
                if (arr[i].el === undefined) {
                    return '沒有當前字段'
                }
                for (var j = 0, ruleLen = vertifyObj[arr[i].alias].length; j < ruleLen; j++) {
                    var ruleObj = vertifyObj[arr[i].alias][j];
                    checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                    _rule = checkRule.shift(); // 獲取校驗算法名稱
                    checkRule.unshift(arr[i].el); // checkRule首位存入校驗的value值
                    checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                    ruleMsg = rules[_rule].apply(null, checkRule);
                    if (ruleMsg) {
                        return ruleMsg;
                    }
                }
            }
        },
        
        // 校驗所有接口
        checkAll: function(vertifyObj,arr) {
            var ruleMsg;
            var checkRule;
            var _rule;
            var reusltMsg = [];
            for (var i = 0, len = arr.length; i < len; i++) {
                // 沒有當前校驗字段
                if (arr[i].el === undefined) {
                    return '沒有當前字段'
                }
                for (var j = 0, ruleLen = vertifyObj[arr[i].alias].length; j < ruleLen; j++) {
                    var ruleObj = vertifyObj[arr[i].alias][j];
                    checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                    _rule = checkRule.shift(); // 獲取校驗算法名稱
                    checkRule.unshift(arr[i].el); // checkRule首位存入校驗的value值
                    checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                    ruleMsg = rules[_rule].apply(null, checkRule);
                    if (ruleMsg) {
                        reusltMsg.push({
                            el: arr[i].el,
                            rules: _rule,
                            message: ruleMsg,
                            alias: arr[i].alias   // 綁定一個別名用處:綁定到具體的一個DOM元素上顯示錯誤信息
                        })
                        break; // 跳出當前循環,不用把當前一個元素上多個驗證不通過結果都存儲起來
                    }
                }
            }
            return reusltMsg.length > 0 ? reusltMsg : false;
        },
        
        // 用戶觸發驗證事件
        trigger: function(params) {
            var self = this;
            for(var key in params.rules) {
                if(params.rules.hasOwnProperty(key)) {
                    var requireEl = document.querySelector(params.el + ' [name="'+key+'"]');
                    var rulesArr = params.rules[key];
                    var resultRules = rulesArr.filter(function(rule) {
                        if(!rule.trigger || rule.trigger === '') return true;
                        if(Array.isArray(rule.trigger)) {
                            return rule.trigger.indexOf('blur') > -1
                        } else {
                            return rule.trigger === 'blur';
                        }
                    }).map(function(rule){return JSON.parse(JSON.stringify(rule))});
                    
                    (function(dom,curDomRules){
                        dom.addEventListener('blur',function(event){
                            var val = dom.value;
                            var ruleMsg = '';
                            for (var j = 0, ruleLen = curDomRules.length; j < ruleLen; j++) {
                                var ruleObj = curDomRules[j];
                                var checkRule = ruleObj.rule.split(':'); // rule規則存在minLenth:6這樣的校驗
                                var _rule = checkRule.shift(); // 獲取校驗算法名稱
                                checkRule.unshift(val); // checkRule首位存入校驗的value值
                                checkRule.push(ruleObj.message); // checkRule末尾加入校驗的message
                                ruleMsg = rules[_rule].apply(null, checkRule);
                                if (ruleMsg) {
                                    var errorDom = dom.nextElementSibling;
                                    errorDom.innerHTML = ruleObj.message;
                                    break; // 跳出當前循環,不用把當前一個元素上多個驗證不通過結果都存儲起來
                                }
                            }
                            if(!ruleMsg) {
                                var errorDom = dom.nextElementSibling;
                                errorDom.innerHTML = '';
                            }
                        },false);
                    })(requireEl,resultRules);
                }
            }
        },
        
        // 添加規則
        addRule: function(ruleName, fn) {
            rules[ruleName] = fn;
        }
    }
})();

// 添加-自定義校驗算法
validate.addRule('isAlphaNum', function(value, errorMsg) {
    if (/[^a-zA-Z0-9]/.test(value)) {
        return errorMsg;
    }
})
    
var rules = {
    userName: [
        {rule: 'isNonEmpty',message: '用戶名不能為空', trigger: 'blur'}, 
        {rule: 'minLength:3',message: '用戶名長度不能小於3位', trigger: 'blur'}, 
        {rule: 'isAlphaNum',message: '用戶名只能是數字跟字母的組合', trigger: 'blur'}
    ],
    password: [
        {rule: 'isNonEmpty',message: '密碼不能為空', trigger: 'blur'},
        {rule: 'minLength:6',message: '密碼的長度不能小於6位', trigger: 'blur'}
    ],
    phoneNumber: [
        {rule: 'isNonEmpty',message: '手機號不能為空', trigger: 'blur'},
        {rule: 'isMobile',message: '手機號碼格式不正確', trigger: 'blur'}
    ]
}

validate.trigger({
    el: '#registerForm',
    rules: rules
})

function submitValidate() {
    var registerForm = document.getElementById("registerForm");
    var rulesArr = [{
            el: registerForm.userName.value,
            alias: 'userName'
        },
        {
            el: registerForm.password.value,
            alias: 'password'
        },
        {
            el: registerForm.phoneNumber.value,
            alias: 'phoneNumber'
        }
    ]
    var resultMsg = validate.checkAll(rules,rulesArr);
    if (resultMsg) {
        for(var re = 0, len = resultMsg.length; re < len; re++) {
            var curResult = resultMsg[re];
            var errorDom = document.querySelector('#registerForm p [name="'+curResult.alias+'"]').nextElementSibling;
            errorDom.innerHTML = curResult.message;
        }
        return false;
    }
    return true;
}

 html代碼:

<form action="" id="registerForm" method="post" onsubmit="return submitValidate()">
    <p>
        <label>請輸入用戶名:</label>
        <input type="text" name="userName" />
        <span class="error"></span>
    </p>
    <p>
        <label>請輸入密碼:</label>
        <input type="text" name="password" />
        <span class="error"></span>
    </p>
    <p>
        <label>請輸入手機號碼:</label>
        <input type="text" name="phoneNumber" />
        <span class="error"></span>
    </p>
    <div>
        <button type="submit">提交</button>
    </div>
</form>

CSS代碼:

<style>
    .error {
        color: red;
    }
</style>

 

 參考地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM