作业|学习资料

JQuery 实现用户名输入的 oninput 查找与有序列表复选框所选项目的批量上移和下移

凝神长老 · 4月13日 · 2019年 900次已读
学校华东师范大学
专业计算机科学与技术
课程服务器维护与网站建设
教师·金健
年份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 绑定同样的函数,即令 usernameoninput 执行 check() 函数,期望得到的效果是,每输入一个字符,就弹出一次对话框,显示 ”你点击了提交“。

<input id="username" type="text" oninput="check()"/><br/>
1554802222875

可以看到,每输入一个字符,就会弹出一个对话框,手动点击确定以后,文本框附加上了当前输入的字符。

这说明,到目前为止,我的网页是能够正常工作的。

同时注意到,如果修改为 onchange,那么需要当焦点移出 username 的时候才会触发函数。

下面就需要绑定 JQuery 了。

首先把问题简化,一步步来。

下面把问题简化为,在 username 下方,给出一个 <p> 标签,内容为 username 的值,即,该段落的内容随着用户输入在文本框中的每一个字符,实时更新。

这个函数非常简单:

function f() {
    username = document.getElementById("username");
    $('#content').html("你输入了:" + username.value);
}

此时,只需要修改输入框的触发函数就行了。

<input id="username" type="text" oninput="f()"/><br/>
1554802622325

下一步,不采用 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() + "不存在");
        }
    });
});
1554803026879
1554803020001

现在程序基本可以正常工作了,就要考虑从后台获取数据了。

从后台获取数据主要有 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,发送的数据是usernamevalue,该字段用 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 `name` FROM `student` 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>
1554805136897
1554805144637

可参看演示视频(见附件)。

至于样式,我可以写出更好看的,但是不是本次作业的重点,我也懒得美化了。

例如

1554805328951
1554805340466

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>
1554987729487

由于上移和下移是一样的,所以这里只详细说明一半。

首先把按钮和事件绑定在一起,然后获取当前点中的一行。

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]));

还有一个问题需要判断,那就是,如果碰到顶了,就不能移动了。

对于上移,很显然能够想到的是,如果 xindex 还是大于 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 条件句的时候,维护一个数组,记录每一个项目新的序号,最后按照新的序号保存回去。

0 0 投票
文章评分
订阅评论动态
提醒
guest
0 评论
行内反馈
查看所有评论