

学校 | 华东师范大学 |
专业 | 计算机科学与技术 |
课程 | 服务器维护与网站建设 |
教师· | 金健 |
年份 | 2019年春 |
JQuery 实现用户名输入的 oninput 查找
本次作业的要求是:
利用 jQuery 的 ajax 函数,异步检测用户名是否存在。
- 前台页上具有一个表单,可以填写用户名和密码
- 在输入用户名的过程中,异步获取所填写用户名在系统中是否存在的信息,并将这些信息显示在用户名输入框旁边
考虑到网络通信的问题,我把 JQuery 的最简 js 下载到了本地同级目录,以 <script src="./jquery.min.js">
形式导入。
从题目中可以很容易看出,要求实现的是 oninput
而不是 onchange
。
首先可以写出整体的布局,那就是 2 个输入框,1 个提交按钮,输入框分别是明文和密文的类型。
<form id="jquerytest"> <input id="username" type="text"/><br/> <input id="password" type="password"/><br/> <input type="button" value="Submit" onclick="check();"/> </form>
提交按钮的动作就是简单地根据是不是输入了内容,弹出不同的对话框,即沿用了前几次作业的结果。
<script> function check(){ input = document.getElementById("username"); form = document.getElementById("jquerytest"); if(input.value != "") alert("你点击了提交"); else alert("不能空"); } </script>
为了测试,可以首先给 username
绑定同样的函数,即令 username
的 oninput
执行 check()
函数,期望得到的效果是,每输入一个字符,就弹出一次对话框,显示 ”你点击了提交“。
<input id="username" type="text" oninput="check()"/><br/>

可以看到,每输入一个字符,就会弹出一个对话框,手动点击确定以后,文本框附加上了当前输入的字符。
这说明,到目前为止,我的网页是能够正常工作的。
同时注意到,如果修改为 onchange
,那么需要当焦点移出 username
的时候才会触发函数。
下面就需要绑定 JQuery 了。
首先把问题简化,一步步来。
下面把问题简化为,在 username
下方,给出一个 <p>
标签,内容为 username
的值,即,该段落的内容随着用户输入在文本框中的每一个字符,实时更新。
这个函数非常简单:
function f() { username = document.getElementById("username"); $('#content').html("你输入了:" + username.value); }
此时,只需要修改输入框的触发函数就行了。
<input id="username" type="text" oninput="f()"/><br/>

下一步,不采用 oninput="f()"
的方式,而是使用 JQuery 的绑定。
$(function(){ $('#username').bind('input propertychange', function() { username = document.getElementById("username"); $('#content').html("你输入了用户名: " + $(this).val()); }); });
需要特别注意 )
和 }
的匹配。
<input id="username" type="text"/><br/>
依然可以正常工作。
接下来就可以做判断了,判断用户名是不是存在。
还是一步一步来,先全部做本地的判断,如果用户输入的是 jxtxzzw
那么就显示用户名存在,否则显示您输入的用户名不存在。
$(function(){ $('#username').bind('input propertychange', function() { username = document.getElementById("username"); if ($(this).val() === 'jxtxzzw'){ $('#content').html("存在用户名" + $(this).val()); } else { $('#content').html("您输入的用户名" + $(this).val() + "不存在"); } }); });


现在程序基本可以正常工作了,就要考虑从后台获取数据了。
从后台获取数据主要有 2 个方法:
- 第 1 个就是 AXIOS 的
- 另一个就是用 ajax
其实是殊途同归,本质上还是发送 POST 请求,我这里用 ajax。
后台处理也是有 2 个主要的思路:
- 一个是根据用户输入的用户名和密码,直接
echo 用户名还不存在
或者echo 该用户名已经存在
,然后前端收到data
以后直接输出 - 另一个是 PHP 返回一个状态码或者 JSON 数组,重新由前端根据状态码或者 TRUE/FALSE 的状态来决定显示什么内容或者渲染什么组件
考虑到封装、前后端分离的特性,我选择了后者。
首先写出发送的代码。
$(function(){ $('#username').bind('input propertychange', function() { username = document.getElementById("username"); $('#content').html("没有找到用户:" + $(this).val()); $.ajax({ async:true, beforeSend:function(){}, data:{username:username.value}, error:function(){}, success:function(){}, type:'POST', url:'./checker.php' }); }); })
这个操作显然是需要同步的,类型是 POST,发送到 checker.php
,发送的数据是username
的 value
,该字段用 username
标识。
发送前不需要做什么 Trim 的工作,而假定后台交互始终是成功的(本机交互),不做异常处理,那么只需要写 success
函数就可以了。
同样,success
函数只做一件事情,那就是 alert("123");
,并写一下后台的程序。
header('Content-Type:application/json; charset=utf-8'); ob_start(); $username = $_POST['username']; $arr = array(); if ( $username == 'jxtxzzw' ) $arr['status'] = 'true'; else $arr['status'] = 'false'; ob_clean(); ob_end_flush(); echo json_encode($arr);
代码非常简单,就是判断 POST 过来的数据是不是 jxtxzzw
,然后决定给出 T
还是 F
。为了避免有无关的错误信息、调试信息输出,这里输出之前用了缓冲区清空。
为了避免浏览器把输出的数据当做纯文本,所以特意在头上声明了类型是 JSON。
特别需要指出的是,这段代码的风格非常不好,所有的判断逻辑过于理想化了,而且尤其是使用了字符串当做结果这是非常不可取的,应该正确使用状态标识。Anyway,只是为了说明一些事情,就这样做了。
这样一来,ajax 的函数只需要根据状态决定输出的内容就可以了。
success:function(res){ if (res['status']==="true") { $('#content').html("用户名存在"); } },
至此,index
页面的内容已经不需要修改了,下面完成 checker.php
。
只差一步,那就是从数据库查询。
MySQL 5.6 以上就不推荐 mysql_
方法了,推荐使用 mysqli
代替,原方法是 Deprecated 了。
另外,SQL 语句有 2 种写法,面向对象的写法是 $mysqli -> query($query)
,而面向过程的写法是 mysqli_query($mysqli, $query)
。
我可能会在我的文章中随意地混用这两种写法。
代码非常简单。
<?php header('Content-Type:application/json; charset=utf-8'); ob_start(); $mysqli = new mysqli("localhost","root","i9loulu7u", "university"); $username = $_POST['username']; $arr = array(); if (mysqli_connect_errno()) { printf("Connect failed: %s\n", mysqli_connect_error()); exit(); } $query = "SELECT <code>{{EJS0}}</code> FROM <code>{{EJS1}}</code> WHERE name='$username'"; $result = $mysqli->query($query); if ( $mysqli->affected_rows >= 1) $arr['status'] = 'true'; else $arr['status'] = 'false'; ob_clean(); ob_end_flush(); echo json_encode($arr);
最后附 index.php
代码。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <script src="./jquery.min.js"> </script> <script> function check(){ input = document.getElementById("username"); form = document.getElementById("jquerytest"); if(input.value !== "") alert("input"); else alert("不能空"); } </script> <script> $(function(){ $('#username').bind('input propertychange', function() { username = document.getElementById("username"); $('#content').html("没有找到用户:" + $(this).val()); $.ajax({ async:true, beforeSend:function(){}, data:{username:username.value}, error:function(){}, success:function(res){ if (res['status']==="true") { $('#content').html("用户名存在"); } }, type:'POST', url:'./checker.php' }); }); }) </script> </head> <body> <form id="jquerytest"> <input id="username" type="text"/><br/> <p id="content"></p> <input id="password" type="password"/><br/> <input type="button" value="Submit" onclick="check();"/> </form> </body> </html>


可参看演示视频(见附件)。
至于样式,我可以写出更好看的,但是不是本次作业的重点,我也懒得美化了。
例如


JQuery 实现有序列表复选框所选项目的批量上移和下移
补充作业的大意是,有一个学生序列/货物序列/条款序列/Whatever序列……
有序的,每一行一个,且提供复选框,用户可以勾选一个或多个,连续或不连续的项目,然后点击“上移”按钮,和“下移”按钮,可以对所有选中的项目批量上移和下移。
例如,如果勾选了 2 3 7,点击一次上移,那么 2 变成 1,3 变成 2,7 变成 6,原来的 1 变成 3,原来的 6 变成 7。
如果再点击上移,由于 2(现在是在第 1 位)已经在顶上了,所以 2 和 3 都不能再往上了,但是 7 (现在是在 6)会继续往上,变成 5、4……直到顶到最上面上不去为止。
纯前端实现的,用的 JQuery 自带的,暂时不考虑调整后的顺序存回数据库。
先写出随机生成一个序列。
<?php $list = array(); for ($i = 0; $i < 20; $i++){ $item = "这是第 " . $i . " 个 jxtxzzw。"; array_push($list, $item); } foreach ($list as $item) { echo "<p> <input type=\"checkbox\" name=\"selected[]\" value='$item'> $item </p>"; }
然后前端的布局就是 2 个按钮和一个内容。
<body> <button id="shiftToPrev">上移</button> <button id="shiftToNext">下移</button> <div id="content"></div> </body>
内容用 JQuery 从 PHP 获取。
<script> $.get("sort.php", function(data){ $("#content").html(data); }); </script>

由于上移和下移是一样的,所以这里只详细说明一半。
首先把按钮和事件绑定在一起,然后获取当前点中的一行。
let currentLine = $('input[type="checkbox"]:checked').parents("p");
这句话是,在输入框中表示被勾选的那部分单元,找到它所在的那个 <p>
标签。
如果是做成了表格的形式,那么这里就是
let currentLine = $('input[type="checkbox"]:checked').parents("tr");
接下来是一个遍历,对所有这些项目,每一个都做一次上移。
for (let x = 0; x < currentLine.length; x++){
移动的时候需要注意一个技巧。
上移的时候,要从后往前移动。
例如,如果选上了 2 和 3,由于 checkbox
保存的顺序是反的,所以是 [3, 2]
,这时候必须反着处理。
必须先把 2 移动到 1,1 移动到 2,整个队列变成 2 1 3,然后把 3 往前移动,把 1 往后移动,变成 2 3 1。
如若不然,那就死循环了:1 2 3,把 3 往上,变成 1 3 2,然后下一个是处理 2,把 2 往上,变成 1 2 3。白做。
类似地,如果是下移,也是要反过来,从前往后移动。
确定了 for 循环的遍历顺序以后,就是要做一个移动。
移动直接调用函数。
$(currentLine[x]).prev().before($(currentLine[x]));
.prev()
获取前面一行,那么,对于当前的 x
,获取前面一行,在那一行的前面放上自己,也就是把自己和对方交换了位置。
对于下移,也是一样的。
$(currentLine[x]).next().after($(currentLine[x]));
还有一个问题需要判断,那就是,如果碰到顶了,就不能移动了。
对于上移,很显然能够想到的是,如果 x
的 index
还是大于 0 的,那么就可以移动。
对于下移,同样的,如果还没有大于元素个数,就可以下移。
但是!必须要考虑的是,如果当前在处理的是第 i 行,那么在它前面就有 length – i 行(被选中的一共有 length 个,由于是反着处理的,所以在他前面有 length – i 行),那么这个项目最多最多移动到 length – i 的位置。
类似的,往下移动,也最多最多移动到 lenngth - x
个。
$(document).ready(function(){ $("#shiftToPrev").bind("click", function(){ let currentLine = $('input[type="checkbox"]:checked').parents("p"); for (let x = currentLine.length - 1; x >= 0; x--){ if($(currentLine[x]).index() >= currentLine.length - x) $(currentLine[x]).prev().before($(currentLine[x])); } }); });
可以看演示视频。
<html> <head> <!-- 我比较习惯在 head 先声明是 UTF-8,然后声明 X-UA-Compatible--> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <script src="./jquery.min.js"> </script> <script> $.get("sort.php", function(data){ $("#content").html(data); }); </script> <script> $(document).ready(function(){ $("#shiftToPrev").bind("click", function(){ let currentLine = $('input[type="checkbox"]:checked').parents("p"); for (let x = currentLine.length - 1; x >= 0; x--){ if($(currentLine[x]).index() >= currentLine.length - x) $(currentLine[x]).prev().before($(currentLine[x])); } }); }); $(document).ready(function(){ $("#shiftToNext").bind("click", function(){ let length = 20; let currentLine = $('input[type="checkbox"]:checked').parents("p"); for (let x = 0; x < currentLine.length; x++){ if($(currentLine[x]).index() < length - x - 1) $(currentLine[x]).next().after($(currentLine[x])); } }); }); </script> </head> <body> <button id="shiftToPrev">上移</button> <button id="shiftToNext">下移</button> <div id="content"></div> </body> </html>
至于最后怎么保存回去,有一个简单的想法,那就是,每一次触发 if 条件句的时候,维护一个数组,记录每一个项目新的序号,最后按照新的序号保存回去。