jQuery EasyUI从零开始学
上QQ阅读APP看书,第一时间看更新

2.1 文本框简介

文本框通常用来接收用户输入的数据。我们先来看一个使用HTML设计的登录页面,部分代码如下:

01  <div>账号<input  type="text"></div>
02  <div>密码<input  type="password"></div>
03  <button>提交</button>

运行结果如图2.1所示。

图2.1 HTML登录页面

读者先想一想这个登录页面有哪些问题。

首先我们没有限制账号、密码文本框为必填字段,这就导致登录用户可以什么也不输入就向服务器发送一个无效的登录请求。

其次如果后端开发人员设计的登录校验SQL语句为:

SELECT * FROM accounts WHERE username='账号' AND password = '密码'

正常情况下用户在账号输入框内输入"admin",在密码输入框内输入"password",后台执行的SQL语句就为:

SELECT * FROM accounts WHERE username='admin' AND password = 'password'

但是如果在账号输入框内输入"admin' AND 1=1 /*",在密码输入框内输入任意字符串,那么后台执行的SQL语句就变成了:

SELECT * FROM accounts WHERE username='admin' AND 1=1 /* and password = 'aaa'

可以看到数据库实际执行的SQL为:

SELECT * FROM accounts WHERE username='admin' AND 1=1

“/*”后面的SQL语句被当作注释而忽略掉了,此时用户就可以绕开密码登录系统。

提示

SQL注入以及XSS攻击等常见的网络攻击手段,其根本原理就是用户输入的数据没有经过充分的检查和过滤,意外变成了代码被执行,我们在设计表单的各个输入控件时,一定要进行相应的过滤,如限制用户只能输入数字、用户输入长度不能超过指定范围等。

要解决上述问题我们必须限制账号、密码文本框的输入内容,例如限制账户、密码不能为空;限制用户输入的长度不能超过指定值,此外还需要限制账号文本框的输入仅能为字母、数字或者下画线。在提交表单前,我们还需要检查每个字段的输入是否合法。要做到这些我们需要设计大量的JavaScript逻辑进行判断,这无疑增加了前端开发的难度。

针对这个开发难点,EasyUI提供了验证框(ValidateBox)来帮助开发者对用户输入的内容进行验证。

2.1.1 验证框(ValidateBox)

验证框是为了防止提交无效字段而设计的,当用户输入无效值时,它将改变背景颜色,并且显示警示图标和提示消息。验证框的默认配置定义在$.fn.validatebox.defaults中。

提示

许多初学者会误以为文本框(TextBox)为EasyUI中最基本的输入框,验证框扩展于文本框。其实在EasyUI中文本框是扩展于验证框的一个输入框,一旦混淆了两者之间的扩展关系,就会产生诸如如何给验证框加上图标等困惑。关于EasyUI中的依赖和扩展关系,本书将会在2.1.2小节详细讲解。

1. 创建验证框

使用标记创建验证框的方法如下:

<input id="v" class="easyui-validatebox"
data-options="required:true,validType:'email'">

使用JavaScript创建验证框的方法如下:

01  <input id="v">
02       $('#v').validatebox({
03             required: true,
04             validType: 'email'
05       });

2. 验证框属性

验证框常用的属性说明见表2.1。

表2.1 验证框常用属性说明

提示

通常我们称光标进入某个组件时,该组件获得焦点;当光标离开组件时,该组件失去焦点。

validType属性定义该字段的验证类型,例如email、url、length等。当验证单个规则时,validType属性的值为字符串类型,如validType:'email'。当验证多个规则时,validType属性的值为数组类型,如validType:['email','length[0,20]']。EasyUI提供的验证规则有:

  • email:检查输入是否为邮箱格式。
  • url:检查输入是否为合法的地址格式。
  • length[0,10]:检查输入的字符长度是否在指定范围区间。
  • remote['http://.../check.php','paramName']:发送ajax请求来验证输入值,验证通过时返回'true'。

提示

length是按照字符计算长度,而非字节。字符与字节的区别在于:一个汉字和英文字母都只算一个字符,而一个汉字占两个字节以上,一个英文字母只占一个字节。

对于EasyUI未支持的验证规则,开发者也可以自定义验证规则,如下代码自定义一个验证两次密码输入是否一致的规则:

01  <input  id="pw1"  name=" pw1"  type="password"  class="easyui-validatebox"
02  data-options="required:true"><!—密码文本框A-->
03  <input  id="pw2"  name="pw2"   type="password"  class="easyui-validatebox"
04     required="required" validType="equals['#pw1]"> <!—密码文本框B-->
05   <script>
06   $.extend($.fn.validatebox.defaults.rules, {
07          equals: {
08            validator: function(value,param){
09            return value == $(param[0]).val();
10          },
11          message: '两次密码输入不一致'
12       }
13     });
14  </script>

其中$.extend($.fn.validatebox.defaults.rules,{})函数的意思是在EasyUI默认的验证规则中添加我们自定义的验证规则。equals为我们自定义的验证规则名称,validator函数中value参数为密码文本框B的值。param为传递的参数;是一个数组,本例中传输的参数为#pw1,它是密码文本框A的id,通过id可以获取密码文本框A的值$(param[0]).val()。最后判断其与密码文本框B的值是否相等,如果相等的话返回true,此时验证通过;如果不相等的话,返回false,同时将显示message中定义的验证失败提示内容。

提示

使用自定义验证规则时,最重要的是理解validator函数的用法,其中value参数是验证字段的值,param是其附带的数据。

3. 验证框事件

验证框常用事件说明见表2.2。

表2.2 验证框常用事件说明

4. 验证框方法

验证框常用方法说明见表2.3。

表2.3 验证框常用方法说明

提示

enableValidation和disableValidation仅仅是启用/禁用验证,设置disableValidation为true后不会对用户的输入进行验证,而disable则禁用整个验证框,用用用户无法进行输入操作。

readonly可以启用或者禁用只读模式,例如:

01  $('#v').validatebox('readonly');                // 启用只读模式
02  $('#v').validatebox('readonly',true);          // 启用只读模式
03  $('#v').validatebox('readonly',false);        // 禁用只读模式

isValid方法可以返回当前验证结果,通常用于提交数据前检测用户输入是否通过验证,例如:

$("#v").validatebox('isValid');

接下来我们使用验证框设计一个用户登录页面,部分代码如下:

01  <div style="margin:20px 20px;">
02           账号 <input id="account">
03      </div>
04      <div style="margin:20px 20px;">
05           密码 <input id="password">
06            </div>
07            <div style="margin:20px 150px;">
08                <button id='login'> 登录</button>
09            </div>
10            <script>
11            $(function(){
12                //自定义验证规则,只能输入英文和数字或者下画线
13                $.extend($.fn.validatebox.defaults.rules, {
14                     englishOrNum : {
15                     validator : function(value) {
16                    return /^[a-zA-Z0-9_]{1,}$/.test(value);
17                     },
18                     message : '请输入英文、数字、下画线或者空格'
19                }
20            });
21            $("#account").validatebox({
22                required :true,                            //设置输入不能为空
23                missingMessage :'请输入账号',              //输入为空时显示的提示
24                invalidMessage:'请输入合法的账号格式',    //输入验证失败时显示的提示
25                validType: ['length[5,10]','englishOrNum'],
26                //多个验证规则使用数组表示,长度在5至10个字符,英文、数字、下画线
27                tipPosition:'bottom',                      //提示框的位置
28                validateOnCreate:false,                    //页面加载完成后不进行一次验证
29            });
30
31            $("#password").validatebox({
32                required :true,                            //设置输入不能为空
33                missingMessage :'请输入密码',              //输入为空时显示的提示
34                invalidMessage:'请输入合法的密码格式',   //输入验证失败时显示的提示
35                validType: 'length[6,13]',
36                //单个验证规则使用字符串表示,长度在5至10个字符,英文、数字、下画线
37                deltaX:-10,
38                //提示框向左边便宜10个单位,数值为负数向左偏移,为正数向右偏移。
39                validateOnCreate:false,                    //页面加载完成后不进行一次验证
40            });
41            $("#login").click(function(){
42                //通过isValid方法检查是否验证通过
43                if($("#account").validatebox('isValid')){
44                alert("账号通过验证");
45            }else{
46                alert("账号未通过验证");
47            }
48            if($("#password").validatebox('isValid')){
49                alert("密码通过验证");
50            }else{
51                alert("密码未通过验证");
52            }
53       });
54  });
55  </script>

最终运行结果如图2.2所示。

图2.2 使用验证框设计登录页面

【本节详细代码参见随书源码:\源码\easyui\example\c2\validateLogin.html】

5. 服务器端验证用户输入

验证框可以通过remote规则来向服务器请求远程验证,注意当验证通过时服务器需要返回字符串'true'。通常我们会在自定义规则中使用ajax来请求远程验证,如下代码使用自定义规则来验证账号是否已被注册,部分代码如下:

01  //该规则用于验证账号是否已被注册
02  accountvalidate : {
03       validator : function(value, param) {
04       //获取用户输入的账户名
05           var account = value.trim();
06           var result;//保存验证的结果
07           $.ajax({
08                type : 'post',
09                async : false,//设置同步请求
10                url : 'server/checkaccount.php',
11                data : {
12                     //向服务器传递的参数,php中可以使用$_POST['account']来获取该值
13                     "account" : account
14                     },
15                success : function(data) {
16                     //data为服务器处理完毕后传递给客户端的值
17                         result = data;
18                }
19           });
20           //resault为true时验证通过
21           if(result=='0'){
22                return true;
23           }
24           else{
25                return false;
26           }
27       },
28       message : '用户名已经被占用'
29  },

【本节详细代码参见随书源码:\源码\easyui\example\c2\remoteValidate.html】

提示

使用服务器端验证时必须设置ajax为同步请求。所谓的同步请求,就是必须获取到服务器返回的值后JavaScript代码才会向下执行,否则会一直等待服务器处理结果。因为验证规则中必须通过服务器返回的结果来判断验证是否通过,因此此时需要设置其为同步请求。

读者可以运行实例程序,在账号中输入sj123、xiaom11、admin、vsi1sk,此时会出现用户名已被占用的提示。

2.1.2 文本框(TextBox)

回到图2.1中,我们使用HTML创建了一个登录页面,在2.1.1小节中带领读者使用EasyUI验证框解决了如何验证用户输入的问题。使用HTML开发还面临着另一个巨大的挑战,就是页面美观问题,通常前端开发人员都需要编写大量的CSS来美化页面。由于CSS编写规范不统一,经常会出现不同的CSS文件冲突,从而导致网站整体设计无法达到预期效果。例如,在图2.2所示的登录页面中通过给验证框添加外边框来进行简单的页面排版。文本框会使用指定的主题样式对组件进行渲染,从而节省开发者的美化时间。

文本框的依赖关系如下:

  • validatebox
  • linkbutton

文本框扩展于:

  • validatebox

文本框的默认配置定义在$.fn.textbox.defaults中。

1. 创建文本框

使用标记创建文本框的方法如下:

<input  class= "easyui-textbox" >

使用JavaScript创建文本框的方法如下:

01  <input  id="tb"  type="text ">
02  $('#tb').textbox();

2. 文本框属性

文本框常用的属性说明见表2.4。

表2.4 文本框常用属性说明

提示

文本框继承了验证框全部属性、事件和方法,在实际开发中我们几乎不会直接使用到验证框,而由文本框派生出各类丰富的EasyUI组件。

在下面的内容中,本书将详细讲解文本框的属性、事件和方法,在本节末尾介绍属性、事件和方法的含义,并带领读者探讨EasyUI中的依赖关系。

首先来看一下width、height属性,从字面意思可以理解这是一个设置文本框尺寸的属性,可以通过比例或者固定的像素值来设置宽度,使用像素值来设置高度。例如:

<input  class="easyui-textbox"  data-options="width:’90%’">
<input  class="easyui-textbox"  data-options="width:360,height:20">

提示

此处我们设置的width:100%是相对于它的上一层父元素的宽度比,当设置为比例时应给值加上引号,请看下面示例:

01           <div  id="parent2"  style="width: 500px;">
02             <div  id="parent1"  style="width: 400px;">
03                 <input  class="easyui-textbox"
data-options="width:'90%'">
04             </div>
05         </div>

最终运行结果如图2.3所示。

图2.3 使用比例设置宽度

这个例子里面parent1为文本框的父元素,它的宽度为400px,parent2为parent1的父元素,它的宽度为500px,我们设置文本框的宽度比为90%,这个比例是相对于parent1的,因此文本框的宽度也就是360px。如果组件通过像素值设置尺寸,我们称其为静态布局。如果使用百分比设置尺寸,我们称其为流式布局。

cls参数用于给文本框添加一个新的风格,例如设置文本框的下外边距为10,相关CSS代码如下:

01  <style>
02      .newStyle{
03           margin-bottom:10px;
04      }
05  </style>

给文本框添加该风格的相关代码如下:

01  $('#tb).textbox({
02      cls:'newStyle'
03  });

prompt属性用于当文本框中无任何内容时显示的提示,例如:

$('#tb).textbox({prompt:'请输入账号'});

value属性为文本框加载完毕后显示的初值。

type属性可以设置文本框的输入类型,当设置为password时,用户的输入将会被替换成指定的字符以避免密码泄露。

label为文本框中的一个标签,在图2.2所示的例子中,“账号”“密码”这些提示用户输入的字符串通常会写在对应组件的前面,但是当这些字符串长度不一致时页面就会变得混乱,如图2.4所示。

图2.4 一个排版混乱的页面

通过label属性可以解决这个问题,其中labelWidth为标签的宽度,labelPosition为标签的显示位置,labelAlign为标签的对齐方式,详细的用法示例如下:

01      <div><input id="nickname"></div>
02      <div><input id="phone"></div>
03  <script>
04  $(function(){
05      $('#nickname').textbox({
06           label:'昵称',
07           labelPosition:'left',//显示在文本框的左侧
08           labelAlign:'right',  //右侧对齐,字符串的最后一个字符对齐
09           width: 300,
10           cls:'newStyle'
11      });
12      $('#phone').textbox({
13           label:'手机号码',
14           labelPosition:'left',
15           labelAlign:'right',
16           width: 300,
17      });
18  });
19  </script>

最终运行结果如图2.5所示。

图2.5 使用标签对齐字符串

icons可以给文本框添加图标,icons为包含icons对象的数组,icons对象有如下属性:

  • iconCls:图标类型。
  • disabled:定义单击图标后是否触发事件。
  • handler:单击图标后触发的事件。

具体的代码示例如下:

01  $('#tb').textbox({
02       icons:[
03          {
04              iconCls:'icon-man',
05              handler:function(e){
06                   alert("图标被单击");
07              }
08          },
09      ],
10  });

最终运行效果如图2.6所示。

图2.6 带图标的文本框

iconAlign、iconWidth属性定义了图标的对齐方式以及宽度,使用代码如下:

01  $('#tb').textbox({
02      icons:[
03           {
04                iconCls:'icon-man',
05                handler:function(e){
06                     alert("图标被单击");
07                }
08           },
09      ],
10  });

上面的例子中使用的图标类型icon-man为EasyUI自带的图标,我们也可以添加一个自定义图标,详细步骤如下:

  • 找到EasyUI框架下themes文件夹中的icons文件夹,将自定义的图标保存到该文件

夹下。

  • 打开themes文件夹下的icon.css文件,在文本末尾添加如下代码:
01  .icon-extend-lock{
02    background:url('icons/extend_lock.png') no-repeat center center;
03  }

其中extend_lock.png为自定义图标的名称,icon-extend-lock为我们自定义的图标的类型名称,使用图标类型名就可以显示我们自定义的图标,代码如下:

01  $(‘#tb’).textbox({
02      icons:[
03           {
04                iconCls:’icon-extend-lock’,
05                handler:function(e){
06                     alert(“图标被单击”);
07                }
08          },
09      ],
10  });

本书在随书资料【\资源\图标\】目录下提供了大量可供读者使用的自定义图标。

文本框允许开发者为其添加一个按钮,buttonText为按钮的名称,buttonIcon为按钮的图标,buttonAlign为按钮的对齐方式。示例代码如下:

01  $(‘#tb’).textbox({
02                buttonText:”按钮”,
03                buttonIcon:’icon-extend-lock’,
04                buttonAlign:’left’//左对齐
05           });

最终运行结果如图2.7所示。

图2.7 带按钮的文本框

3. 文本框事件

文本框常用事件说明见表2.5。

表2.5 文本框常用事件说明

提示

onChange只能在内容发生改变且失去焦点时触发。

4. 文本框方法

文本框常用方法说明见表2.6。

表2.6 文本框常用方法说明

提示

textbox返回的是展示值框对象,因此开发者无法使用该对象重新初始化文本框,关于展示值框的概念请查看2.1.3节内容。如下代码是错误的:

01  var tb = $("#tb").textbox("textbox");
02  tb.textbox({
03        width:100
04  });

运行后会发现在文本框中又嵌套了一个文本框。

5. 属性、方法和事件

一个手机都会拥有尺寸、音量、屏幕等元素,这些是组成一个手机的必要元素,我们称这些元素为属性。手机出厂后通常都会替消费者设置好默认的屏幕亮度以及音量,这一个过程我们称为初始化。在EasyUI中组件的属性在页面加载完毕后就会将其初始化好。如下代码设置文本框的初始值和初始类型属性,代码如下:

01  $('#tb).textbox({
02           value:'初始值',
03           type:’text’
04       });

提示

在jQuery中可以通过$(function(){//页面加载完毕后的代码})的方式来处理页面加载完毕后的代码。

当手机接收到来电消息时,会亮起屏幕并且播放响铃,这一过程叫作事件。事件必须有特定的消息才会触发,事件也是在初始化时设置,例如当文本框中的内容发生改变时会触发onChange事件,写法如下:

01  $('#tb).textbox ({
02       onChange:function(newValue,oldValue){
03       }
04  });

使用者可以调节手机的音量大小以及屏幕显示的亮度,这一过程称为方法。方法通常是在属性初始化后改变属性的值,在文本框中的editable、disabled、readonly、width、height、value等属性都可以通过对应的方法将其改变,如resize方法改变宽度,initValue方法重新设置初始值等。如下代码设置文本框为只读模式。

$('#tb').textbox('readonly',true);

使用者可以在手机设置功能中查看当前手机的各种配置,也就是说方法不仅可以修改属性的值也可以查看属性的值。例如,options方法可以查看当前文本框的全部配置,我们称组件的当前配置对象为其选项对象。

使用者可以在手机上设置闹铃,闹铃只会在指定的时间才会触发,因此闹铃是一个事件,而使用者设置闹铃这一过程是一个方法,因此通过方法同样可以增加事件。文本框中textbox方法可以绑定任意的事件。如下代码给文本框绑定一个键盘按下的事件:

01  $('#tb').textbox("textbox").bind("keydown",function(e){
02      var v = e.keyCode;//当前按键的ASCII码
03  });

6. 依赖与扩展

依赖更多的是含有一种组合的含义,而扩展更多的是继承含义,如果组件A依赖于组件B,说明组件A由组件B组成。如果组件A扩展于组件B,那么组件A中可以使用组件B的全部属性、事件、方法。关于依赖与扩展的含义本书将在第6章中做进一步讲解,目前读者仅需了解扩展组件可以使用被扩展组件的全部属性、方法、事件,例如文本框扩展于验证框,此时我们可以在文本框中使用验证框属性required,例如:

<input class= "easyui-textbox" data-options ="required:true" >

所有的组件都拥有options方法,该方法以JSON格式返回一个选项对象,所谓的选项对象就是指组件初始化完毕后的配置。可以通过下面的JavaScript函数打印文本框的options对象:

01  function writeObj(obj){
02       var description = "";
03       for(var i in obj){
04            var property=obj[i];
05            description+=i+" = "+property+"\n";
06       }
07       alert(description);
08  }
09  writeObj($('#tb').textbox('options'));

运行结果如图2.8所示。

图2.8 文本框选项对象的值

提示

EasyUI组件通常会使用对象作为属性、事件或者方法的参数,如果读者无法明确参数的含义,可以使用writeObj函数打印参数,或者使用console.log()函数在控制台中打印参数。

options是一个JSON格式的对象,我们可以通过相应的方法获取指定的字段值,例如通过options方法获取组件的required属性值,代码如下:

01  var option = $('#tb').textbox('options');
02  var required = option.required;

7. 默认配置

每个组件都会定义自己的默认配置,每当初始化组件时都会使用默认配置来初始化那些开发者未设置的属性或事件,例如我们可以获取文本框的默认宽度,代码如下:

$.fn.textbox.defaults.width

8. EasyUI组件中的值

在EasyUI组件中有三种值,分别是:

  • 输入值。用户输入的值可以是任意的字母。
  • 存储值。根据用户输入不可信原则,用户输入的值必须经过相应的过滤和限制,存储值是将用户的输入进行过滤以及解析后的最终值。
  • 展示值。用户并不希望显示一些枯燥的数字,例如用户更希望看到XX年XX月XX日格式的日期,而非一串时间戳数字,展示值就是将存储值格式化为指定的格式后的值。

我们称用户输入值为Input,存储值为Value,展示值为Text。可以通过initValue、getValue、setValue方法来初始化存储值、获取存储值以及设置存储值。可以通过getText、setText方法来获取展示值、设置展示值。关于存储值和展示值的区别,下面举个简单的例子。中国的用户更希望看到例如XX年XX月XX日这样格式的日期,然而对于计算机而言,更希望处理时间戳格式的日期。此时我们会设计两个输入框,其中一个输入框展示XX年XX月XX日格式的日期,另一个输入框通常会隐藏起来,保存计算机能理解的时间戳,最终在提交表单时将时间戳传输给服务器。将存储值转化成展示值的过程称为格式化(formatter),将输入值转化成存储值的过程称为解释(parser)。EasyUI中通常会使用包含Value的字符串来命名存储值的属性或者方法,使用包含Text的字符串来命名展示值的属性或者方法。读者在后续的学习中应当作到望文生义。

提示

在文本框中必须先设置存储值,之后才能设置展示值。如下代码运行后会发现存储值和展示值都被设置为2。

01 $('#tb').textbox('setText',"1");
02 $('#tb').textbox('setValue',"2");

9. EasyUI方法的链式操作

EasyUI组件的方法(除获取数据的方法外)返回的为该组件对象,因此可以对EasyUI方法使用链式操作,例如:

$('#tb').textbox('setValue',"2").textbox('setText',"1");

2.1.3 密码框(PasswordBox)

EasyUI提供了专门用于输入密码的组件密码框。密码框提高了用户的交互性,它通过使用指定的字符来替换用户输入的密码从而防止用户密码泄露,密码框的右侧是一个眼状图标,可以通过单击该图标显示用户输入的密码。

密码框的依赖关系如下:

  • textbox

密码框扩展于:

  • textbox

密码框的默认配置定义在$.fn.passwordbox.defaults中。

1. 密码框用法

使用标记创建密码框的方法如下:

<input  class="easyui-passwordbox" >

使用JavaScript创建密码框的方法如下:

01  <input id="pb" type="text" style="width:300px">
02  $(function(){
03      $('#pb').passwordbox({
04          prompt: 'Password',
05          showEye: true
06      });
07  });

2. 密码框属性

密码框常用属性说明见表2.7。

表2.7 密码框常用属性说明

3. 密码框事件

密码框在文本框的基础上无新增事件。

4. 密码框方法

密码框常用方法说明见表2.8。

表2.8 密码框常用方法说明

2.1.4 数字框(NumberBox)

数字框用于过滤用户的输入值使用户仅能输入数字,可以把存储值转换为不同类型的展示值(比如:数字、百分比、货币,等等)。可以通过formatter方法来自定义展示格式,通过parser方法将输入值解析成存储。

数字框的依赖关系如下:

  • textbox

数字框扩展于:

  • textbox

数字框的默认配置定义在$.fn.numberbox.defaults中。

1. 数字框的用法

使用标记创建数字框的方法如下:

<input type="text" class="easyui-numberbox" value="100"
data-options="min:0,precision:2">

使用JavaScript创建数字框的方法如下:

01  <input type="text" id="nn">
02  $('#nn').numberbox({min:0,precision:2});

2. 数字框属性

数字框常用属性说明见表2.9。

表2.9 数字框常用属性说明

其中min、max、precision属性主要用于控制输入值与存储值之间的转换规则,例如设置precision的值为2,那么用户如果输入的是3.12345则会被自动过滤成3.12。filter属性主要用于过滤输入值,其参数e是一个事件对象,可以通过e.keyCode获取当前按下的键的ASCII码,返回true则接收该字符,返回false则禁止输入该字符。

decimalSeparator、groupSeparator、prefix、suffix参数则为数字框内置的一些将存储值转换成展示值的规则,例如设置prefix值为美元符“$”,当存储值为1时,展示值则为“$1”。

formatter、parser属性可以用来自定义输入值、存储值以及展示值之间的转化规则。formatter用于将存储值格式化为展示值,parser用于将输入值解析成存储值。初学者在使用这两个属性时经常会出现一系列的问题,这是因为没有理顺这两个属性触发的时机,下面我们将重点讲解,先看下面的代码:

01      <input type="text" id="nn">
02      <script>
03      $(function(){
04           $('#nn').numberbox({
05                prefix:'$',
06                //formatter中接收的是一个存储值
07                formatter:function(value){
08                    alert("formatter");
09                    return parseInt(value)+1;
10                },
11                //parser中接收的是一个输入值
12                parser:function(s){
13                    alert("parser");
14                    return parseInt(s)-1;
15                }
16           });
17      });
18  </script>

读者可以将其复制到自己的文件中运行,运行这段代码后我们可以发现:

  • prefix属性无法定义展示值前缀。
  • 当页面刷新时会先执行parser中定义的方法,再执行一次formatter。
  • 当文本框内的内容发生改变时,会依次执行parser、parser、formatter、formatter属性中的方法。

第一个问题很容易理解,因为数字框默认在formatter属性方法中将存储值转化成展示值,在parser属性中将输入值转化成存储值。因此设置prefix属性后数字框会在默认的parser属性方法中检查用户输入值是否有指定前缀,有的话就将前缀移除并将处理后的值作为存储值保存,然后在formatter方法中的存储值前面加上前缀。上述代码中重新定义了parser和formatter属性,此时数字框默认的parser以及formatter属性将会被覆盖,因此prefix属性会失效。

在文本框中向读者讲解了值的概念,其实文本框在创建时会新增两个输入框,此时HTML如下:

01  <!—初始化框,开发者编写的标记,用于保存初始化配置和存储值,
02  通常也会将选项对象绑定到初始化框上->
03  <input type="text" id="nn" type="hidden">
04  <!—展示值框,文本框新增的标记,用于存放展示值-->
05  <input class="textbox-text">
06  <!---存储值框,文本框新增的标记,用于存放存储值-->
07  <input type="hidden" class="textbox-value">

读者可以发现,其实文本框向用户显示的仅仅是展示值框,而初始化框和存储值框会被隐藏,也就是说用户其实是在展示值框中进行输入的。此时我们再看这段代码:

01  <input type="text" id="nn">
02  <script>
03  $(function(){
04       $('#nn').numberbox({
05            prefix:'$',
06       });
07  });
08  </script>

这段代码的含义是在数字前面加上一个美元符$前缀,它的运行原理如下:当组件加载时会先将初始化框中的初始值使用parser属性中的方法进行解析,如果初始值是$111的话会将其解析成111,如果是其他格式的话例如222则仍然会解析成222并将解析后的值保存到存储值框中,接下来formatter属性会取出存储值,并在其前面加上前缀后保存到展示值框中显示。具体的过程如图2.9所示。

提示

由于用户输入值有可能是合法展示值,也有可能是合法的存储值,还有可能是一些非法值,所以在parser中需要对用户输入值进行判断和过滤。

图2.9 数字框初始化流程图

当数字框失去焦点时,数字框会调用一次fix方法,该方法中调用一次parser属性方法,将用户输入数据转换成存储值,接着该方法中会使用数字框的setValue方法保存存储值,但是在setValue方法中也会调用一次parser属性方法,这是因为setValue方法可以被开发者直接调用,例如:

$('#nn').numberbox('setValue',’$11’)

因为该方法中仍然需要对传入的值进行解析,并将其转化成合法的存储值,这就是为什么parser属性会被调用两次的原因。接着会使用一次formatter属性方法格式化存储值,注意在处理完毕后会再调用一次formatter属性方法格式化存储值,这两次的调用区别是,第一次格式化的存储值是parser处理完毕后返回的值,第二次格式化的存储值是通过getValue方法获取的数字框存储值。

如果读者目前无法完全理解这两个属性的话也没关系,对于parser属性和formatter属性,读者只需要记住一句话,parser属性是将用户输入的数据解析成合法的存储值,而formatter是将存储值格式化为展示值。下面我们利用这两个属性给文字添加美元符前缀,部分代码如下:

01       <input type="text" id="nn" value="111">
02       <script>
03       $(function(){
04           $("#nn").numberbox({
05                     parser:function(s){
06                         s = $.trim(s.replace("$",""));
07                         return s;
08                     },
09                     formatter:function(value){
10                         return '$'+value;
11                     }
12           });
13       });
14  </script>

通过上述的讲解,读者必须理解如下两个知识点:

  • 所有直接或间接扩展于文本框的组件向读者展示的都是其展示值框,由于初始化框被隐藏,因此除了部分样式外,一切在初始化框中设置的样式都不能生效,此时可以使用cls属性给展示值框添加新的风格,不过该风格只适用于展示值框,并不适用于文本框的标签。通常我们使用<div>标记作为文本框类组件的父容器,并在父容器中添加相关的风格。由于初始化框被隐藏,我们无法通过选择器来选中指定的文本框组件并为其绑定事件,因此文本框提供了textbox方法,该方法返回文本框中的展示值框对象,开发者可以为展示值框绑定相关的时间。
  • parser属性是将输入值转换成存储值,用户的输入值可能就是合法的存储值,也可能是展示值,还有可能是非法值,开发者在parser属性中一定要做充分的判断。

3. 数字框事件

数字框在文本框的基础上无新增事件。

4. 数字框方法

数字框常用方法的说明见表2.10。

表2.10 数字框常用方法说明

5. 深入理解数字框的值

我们已经向读者讲解了EasyUI中的三个值,它们分别是输入值、展示值以及存储值,这里讲到数字框实际上由以下三部分组成:

  • 初始化框:用于保存组件初始化的配置以及存储值。
  • 存储值框:用于保存存储值。
  • 展示值框:用于显示展示值,以及接收用户的输入值。

其中初始化框中保存的是初始化的配置以及存储值,一些jQuery开发者习惯使用例如$('#nn').val('11')的方法给数字框赋值,读者可以发现此这种方法其实只是给初始化框赋值,并不会改变数字框的值。但是通过$('#nn').val()方法可以取出数字框的存储值,这是因为存储值也会被保存在初始化框中。这样做的好处很多,例如在提交表单时,服务器端可以直接根据初始化框中的name属性获取数字框的存储值。

展示值框有两个作用,首先它接收用户的输入,也就是说输入值其实是被输入到展示值框中的;其次它向用户显示展示值,用户的输入值与展示值之间的转换在数字框中需要先使用parser属性方法将输入值转换成存储值,再使用formatter属性方法将存储值转化成展示值。

存储值框中会保存存储值,可以通过getValue方法获取其值。

接下来请读者思考自定义验证规则时到底是对数字框的哪个值进行验证呢?请看下面的代码:

01  <input type="text" id="nn" value="1">
02  <script>
03       $(function(){
04           $("#nn").numberbox({
05                validType:"englishOrNum",
06                prefix:'$',
07           });
08           //自定义验证规则,只能输入数字
09           $.extend($.fn.validatebox.defaults.rules, {
10                englishOrNum : {
11                validator : function(value) {
12                  return /^[0-9]{1,}$/.test(value);
13                },
14                message : '请输入数字'
15                }
16           });
17       });
18  </script>

最终运行结果如图2.10所示。

图2.10 带验证的数字框

我们知道该示例中存储值为一个纯数字,而展示值为一个带美元符号前缀的数字,验证规则中自定义了一个验证用户输入是否为数字的规则。可以发现当用户输入一串数字后仍然无法通过验证,这是因为验证方法也会对展示值进行验证,如果我们希望仅仅验证存储值的话,那就必须在自定义验证规则中对展示值进行解析,如下代码所示。

01  $.extend($.fn.validatebox.defaults.rules, {
02       englishOrNum : {
03       validator : function(value) {
04            value = $.trim(value.replace("$",""));//去除前缀
05            return /^[0-9]{1,}$/.test(value);
06       },
07       message : '请输入数字'
08       }
09  });