
| 学校 | 华东师范大学 |
| 专业 | 计算机科学与技术 |
| 课程 | 服务器维护与网站建设 |
| 教师· | 金健 |
| 年份 | 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 条件句的时候,维护一个数组,记录每一个项目新的序号,最后按照新的序号保存回去。
