登录登出页面的跳转和模糊搜索实现

2022-08-02,,,,

登录登出页面跳转

    • 首页 index
    • 注册页 regregister
    • login.php文件
    • register.php文件
    • 用到的封装函数如下
    • 效果图如下

以下内容涉及前端,后端,数据库的内容 对登出登录的数据操作;
注意:因为引入bootstrap里面的页面布局,所以会些零乱,后续会修改这部分。。。

首页 index

功能实现如下:


    登录页功能如下:

    【1】登录登出功能思路:
      1、点击用户名 显示下拉菜单 (注意:需要添加 阻止冒泡 行为 因为第二步会影响第一步)

      2、点击其他任意地方 隐藏下拉菜单 

      3、点击登出 把 用户名 改为 登录状态

      4、点击登录 跳转页面到 登录页面

      5、页面加载之后获取 cookie值 并把cookie的值 赋值给登录按钮的内容

    【2】搜索框的模糊搜索功能思路:
      1、当输入框改变时,获取输入框里面的内容

      2、发送ajax 请求 (注意里面需要携带输入框里面的内容)

      3、收到响应数据 (这里是调用ajax和promise)

      4、判断搜索下拉菜单的显示和隐藏
        4.1 如果有数据,显示
        4.2 如果没有数据,隐藏 并return false 结束函数 不执行下面的代码

      5、拿到后端传过来的数据 并渲染到页面 

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>SB Admin 2 - Dashboard</title>

  <!-- Custom fonts for this template-->
  <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">

  <!-- Custom styles for this template-->
  <link href="css/sb-admin-2.min.css" rel="stylesheet">
  <style>
    #wrapper #content-wrapper {
      overflow-x: visible;
    }

    #loginbtn {
      display: none;
    }

    .p-r {
      position: relative;
    }

    .search-list {
      position: absolute;
      background: rgba(0, 0, 0, 0.3);
      width: 25rem;
      top: 40px;
    }

    .search-list li {
      list-style-type: none;
      line-height: 40px;
      border-bottom: 1px solid #000;
      color: #333;
    }
  </style>
</head>

<body id="page-top">

  <!-- Page Wrapper -->
  <div id="wrapper">

    <!-- Content Wrapper -->
    <div id="content-wrapper" class="d-flex flex-column">

      <!-- Main Content -->
      <div id="content">

        <!-- Topbar 顶部模块 -->
        <nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
          <!-- 搜索模块 -->
          <form class="d-none form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search p-r d-inline-block">
            <div class="input-group">
              <input id="search" type="text" class="form-control bg-light border-0 small" placeholder="Search for..."
                aria-label="Search" aria-describedby="basic-addon2">
              <div class="input-group-append">
                <button class="btn btn-primary" type="button">
                  <i class="fas fa-search fa-sm"></i>
                </button>
              </div>
            </div>
            <ul class="search-list d-none">
              <li>内容</li>
              <li>内容</li>
              <li>内容</li>
            </ul>
          </form>

          <!-- Sidebar Toggle (Topbar) -->
          <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
            <i class="fa fa-bars"></i>
          </button>

          <!-- Topbar Navbar 头部导航栏 -->
          <ul class="navbar-nav ml-auto">

            <div class="topbar-divider d-none d-sm-block"></div>

            <!-- Nav Item - User Information 用户信息 -->
            <li class="nav-item dropdown no-arrow">
              <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false">
                <!-- 用户名 -->
                <span id="username" class="mr-2 d-none small d-lg-inline text-gray-600 ">公羊无衣</span>
                <!-- 登陆按钮 -->
                <span id="loginbtn" class="mr-2 d-none">登录</span>
              </a>
              <!-- Dropdown - User Information  下拉菜单 登出按钮-->
              <div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" id="userDropdownOptions"
                aria-labelledby="userDropdown">
                <a class="dropdown-item" id="logout" href="#" data-toggle="modal" data-target="#logoutModal">
                  <i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
                  登出
                </a>
              </div>
            </li>
          </ul>

        </nav>
        <!-- End of Topbar -->

      </div>
      <!-- End of Main Content -->


    </div>
    <!-- End of Content Wrapper -->

  </div>
  <!-- End of Page Wrapper -->



  <script src="./js/utils.js"></script>
  <script>
    /*
    登录页功能如下:

    【1】登录登出功能思路:
      1、点击用户名 显示下拉菜单 (注意:需要添加 阻止冒泡 行为 因为第二步会影响第一步)

      2、点击其他任意地方 隐藏下拉菜单 

      3、点击登出 把 用户名 改为 登录状态

      4、点击登录 跳转页面到 登录页面

      5、页面加载之后获取 cookie值 并把cookie的值 赋值给登录按钮的内容

    【2】搜索框的模糊搜索功能思路:
      1、当输入框改变时,获取输入框里面的内容

      2、发送ajax 请求 (注意里面需要携带输入框里面的内容)

      3、收到响应数据 (这里是调用ajax和promise)

      4、判断搜索下拉菜单的显示和隐藏
        4.1 如果有数据,显示
        4.2 如果没有数据,隐藏 并return false 结束函数 不执行下面的代码

      5、拿到传过来的数据 并渲染到页面 
    */


    // 1. 点击用户名 显示下拉菜单
    // username 用户名的ID;
    // userDropdownOptions 下拉菜单的ID;
    $("#username").onclick = function (evt) {
      var e = evt || event;
      $("#userDropdownOptions").style.display = "block";
      // 这里是阻止默认行为 (a标签的)
      e.stopPropagation();
    }
    
    // 2. 登出点击 :  d-none 隐藏的类名;  d-lg-inline 显示的类名;
    // 显示登陆按钮,隐藏用户名;
    $("#logout").onclick = function () {
      $("#username").className = "d-none";
      $("#loginbtn").className += " d-lg-inline";
    }

    // 3. 点击外部任意位置,隐藏下拉菜单;
    document.onclick = function () {
      $("#userDropdownOptions").style.display = "none";
    }

    // 4. 点击登录按钮跳转到登陆页面;
    $("#loginbtn").onclick = function () {
      location.href = "./login.html";
    }
    // 5. 页面加载之后获取cookie,把cookie里面的内容放在用户名上。
    // 为啥要用cookie ? 因为要替换掉登录的内容
    window.onload = function () {
      var cookie = getCookie("email");
      if (cookie) {
        $("#username").innerHTML = cookie;
      }
    }

  </script>
  <script>

    // 百度搜索 : 
    // 1. 输入框事件触发 input 
    // 2. 数据改变就发起请求 => 后端发起请求;
    // 3. 拿到数据,渲染页面;

    $("#search").oninput = function () {
      // 1. 获取数据;
      var search_value = this.value;

      // 判断是否输入内容 显示隐藏下拉搜索菜单内容
      if (!search_value) {
        $(".search-list").className = "search-list d-none";
        return false;
      }

      // console.log(search_value) 已经测试没有问题;
      // 2. 发送请求;
      ajax({
        method: "jsonp",
        url: "https://www.baidu.com/sugrec",
        data: {
          pre: 1,
          p: 3,
          ie: "utf-8",
          json: 1,
          prod: "pc",
          from: "pc_web",
          sugsid: "32218,1425,31672,32139,31254,32045,32230,32299,31639",
          wd: search_value,
          req: 2,
          csor: 5,
          cb: "callback",
          _: Date.now()
        }
      })
        .then(function (res) {
          // console.log(res); 已经测试没有问题;
          var list = res.g;
          // 判断list是否有内容 
          // 这里的list 会为undefined 所以以此来判断状态 
          // 如果没有内容 则为undefined  if里面为false  执行else里面语句 隐藏下拉菜单 结束下面全部代码的执行
          // 如果有内容  则if里面为true 执行if里面的语句,显示下拉菜单 并继续向下渲染页面
          if (list) {
            // 让元素显示出来;
            $(".search-list").className = "search-list"
          } else {
            // 让元素隐藏;
            $(".search-list").className = "search-list d-none";
            // 如果没有数据需要渲染则隐藏掉下拉列表;
            return false;
          }

          // 渲染数据 , 拼接页面;
          var html = "";
          list.forEach(function (item) {
            html += `<li>${item.q}</li>`
          })
          $(".search-list").innerHTML = html;
          //逻辑 : 根据 html是否为空判定 searchlist 的显示隐藏;
          // console.log(html);
        })
    }
    
  // 函数节流 : 考虑优化的点
  // var t = null;
  // $("#search").oninput = function(){
  //   if( t !== null){
  //       return false
  //   }
  //   // 1. 获取数据;
  //   var search_value = this.value;
  //   t = setTimeout(function(){
  //     t = null;
  //     if(!search_value){
  //       $(".search-list").className = "search-list d-none";
  //       return false;
  //     }

  //     // console.log(search_value) 已经测试没有问题;
  //     // 2. 发送请求;
  //     ajax({
  //       method : "jsonp",
  //       url : "https://www.baidu.com/sugrec",
  //       data : {
  //               pre:1,
  //               p:3,
  //               ie:"utf-8",
  //               json:1,
  //               prod:"pc",
  //               from:"pc_web",
  //               sugsid:"32218,1425,31672,32139,31254,32045,32230,32299,31639",
  //               wd : search_value,
  //               req:2,
  //               csor:5,
  //               cb:"callback",
  //               _:Date.now()
  //       }
  //     })
  //     .then( function( res ){
  //       // console.log(res); 已经测试没有问题;
  //       var list = res.g;
  //       if(list){
  //         // 让元素显示出来;
  //         $(".search-list").className = "search-list"
  //       }else{
  //         // 让元素隐藏;
  //         $(".search-list").className = "search-list d-none";
  //         // 如果没有数据需要渲染则隐藏掉下拉列表;
  //         return false;
  //       }

  //       // 拼接页面;
  //       var html = "";
  //       list.forEach( function( item ){
  //         html += `<li>${item.q}</li>`
  //       })
  //       $(".search-list").innerHTML = html;
  //       //逻辑 : 根据 html是否为空判定 searchlist 的显示隐藏;
  //       console.log(html);
  //     })
  //   } , 500)
  // }
  
  </script>

</body>

</html>

注册页 regregister

功能实现如下:

 
  注册页如下:

  【1】注册功能思路
    1、给注册按钮绑定点击事件 (因为是异步程序,所以这里使用asyncawait)

    2、因为注册按钮为a标签 , 所以 阻止 的默认跳转事件行为

    3、获取输入框中的登录值和密码值

    4、把数据发送给前端 通过 fetch 发送请求
      4.1 fetch中的 第一个参数为url 第二个参数是 请求方式和body值配置,第三个参数 是设置header

    5await 接收响应的数据 并把数据的 json类型 转为 对象或数组

    6、判断数据是否成功
      6.1 如果成功 跳转到登录页面
      6.2 如果不成功 则弹出错误 (注册有误)
 
<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>SB Admin 2 - Register</title>

  <!-- Custom fonts for this template-->
  <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
  <link
    href="https://fonts.lug.ustc.edu.cn/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
    rel="stylesheet">

  <!-- Custom styles for this template-->
  <link href="css/sb-admin-2.min.css" rel="stylesheet">

</head>

<body class="bg-gradient-primary">

  <div class="container">

    <div class="card o-hidden border-0 shadow-lg my-5">
      <div class="card-body p-0">
        <!-- Nested Row within Card Body -->
        <div class="row">
          <div class="col-lg-5 d-none d-lg-block bg-register-image"></div>
          <div class="col-lg-7">
            <div class="p-5">
              <div class="text-center">
                <h1 class="h4 text-gray-900 mb-4">Create an Account!</h1>
              </div>
              <form class="user">
                <div class="form-group">
                  <input type="email" class="form-control form-control-user" id="inputEmail"
                    placeholder="Email Address">
                </div>
                <div class="form-group">
                  <input type="password" class="form-control form-control-user" id="inputPassword"
                    placeholder="Password">
                </div>
                <a href="login.html" id="register_btn" class="btn btn-primary btn-user btn-block">
                  注册
                </a>
                <hr>
              </form>
              <hr>
              <div class="text-center">
                <a class="small" href="login.html">已经有账号了?请登录</a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

  </div>

</body>
<script src="./js/utils.js"></script>
<script>

  /*
  注册页如下:

  【1】注册功能思路
    1、给注册按钮绑定点击事件 (因为是异步程序,所以这里使用async和await)

    2、因为注册按钮为a标签 , 所以 阻止 的默认跳转事件行为

    3、获取输入框中的登录值和密码值

    4、把数据发送给前端 通过 fetch 发送请求
      4.1 fetch中的 第一个参数为url 第二个参数是 请求方式和body值配置,第三个参数 是设置header

    5、await 接收响应的数据 并把数据的 json类型 转为 对象或数组

    6、判断数据是否成功
      6.1 如果成功 跳转到登录页面
      6.2 如果不成功 则弹出错误 (注册有误)
  */


  // 点击按钮 , 阻止默认事件;
  // 发送请求给后端;
  $("#register_btn").onclick = async function (evt) {
    // 阻止默认事件;
    var e = evt || event;
    e.preventDefault();
    // 获取输入框之中的数据;
    var email_value = $("#inputEmail").value;
    var password_value = $("#inputPassword").value;
    // 把数据发送到后端;
    /* fetch 有三个参数
      第一个参数为 url 
      第二个参数为 请求方式和数据
      第三个参数为 设置header 
    */
    let response = await fetch("../server/register.php", {
      method: "POST",
      body: formate({
        email: email_value,
        password: password_value
      }),
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      }
    })
    // 接收后端返回响应的数据 并使用json方法把数据改为对象类型 
    let data = await response.json();
    console.log(data)

    // 根据后端返回的数据,判断用户名是否可以跳转到登录页 
    // 如果数据判断是false 则提示注册信息有误 
    // 有误的可能原因:已经存在注册过
    if (data.type === "success") {
      location.href = "./login.html";
    } else {
      alert("注册信息有误");
    }
  }

</script>

</html>

login.php文件

<?php

/*
  登录页
  后端思路:
  1、先获取前端传过来的数据,就是用户信息
  2、链接数据库,选择数据库
  3、操作数据库
    3.1 编写sql语句
    3.2 执行sql语句
    3.3 返回资源类型进行遍历处理
  4、关闭数据库
  5、判断返回的资源类型遍历的结果 是否存在数据库中
    5.1 如果存在    返回json类型数据 成功
    5.2 如果不存在  返回json类型数据 失败
*/

  # 接受前端的用户信息;
  $email = $_POST["email"];
  $password = $_POST["password"];

  # 链接数据库 , 比对数据库之中是否存在这条信息;
  # 1. 建立链接
  $con = mysql_connect("localhost", "root" , "nfq123456");
  # 2. 选择数据库 
  mysql_select_db("udata");
  mysql_query("set names utf8");
  # 3. 操作数据库
  // 1. 编写 sql 语句;
  // 2. php的API去执行sql语句; 
  // - 字段名需要使用 `` 引起来 
  // - 关键字要大写
  // $sql = 'SELECT `email` FROM `user` WHERE `email`="'.$email.'" AND `password`="'.$password.'"';
  // 这样外面是 双引号 里面变量用 单引号 也可以
  $sql = "SELECT `email` FROM `user` WHERE `email`='$email' AND `password`='$password'";

  $res = mysql_query($sql);
  // # 4. 把返回的资源类型进行遍历处理
  $arr = mysql_fetch_array( $res );
  mysql_close($con);
  // # 如果在数据库之中存在这条数据表示登录成功;
  if($arr){
      # 登录成功
      die('{"type":"success"}');
  }else{
      # 登录失败;
      die('{"type":"error"}');
  }
?>

register.php文件

<?php

/*
  注册页 
  后端的思路:
  1、获取前端传过来的数据,这里是用户名和密码
  2、连接数据库,并选择数据库
  3、操作数据库
     3.1 编写sql语句
     3.2 执行sql语句
     3.3 返回的资源类型进行遍历处理
  4、判断数据是否在存在,有就关闭数据库 并返回json数据 die结果
  5、把注册的 数据 (用户名和密码) 插入 数据库中
     5.1 插入数据到数据库中
     5.2 执行sql语句
  6、判断是否插入成功 
*/

  # 接受前端的用户信息;
  $email = $_POST["email"];
  $password = $_POST["password"];

  # 链接数据库 , 比对数据库之中是否存在这条信息;
  # 1. 建立链接
  $con = mysql_connect("localhost", "root" , "nfq123456");
  # 2. 选择数据库 
  mysql_select_db("udata");
  mysql_query("set names utf8");
  # 3. 操作数据库
  // 1. 编写 sql 语句;
  // 2. php的API去执行sql语句; 
  // - 字段名需要使用 `` 引起来 
  // - 关键字要大写
  // $sql = 'SELECT `email` FROM `user` WHERE `email`="'.$email.'"';
  // 这样外面是 双引号 里面变量用 单引号 也可以
  $sql = "SELECT `email` FROM `user` WHERE `email`='$email'";

  $res = mysql_query($sql);
  // # 4. 把返回的资源类型进行遍历处理
  $arr = mysql_fetch_array( $res );

  if($arr){
      mysql_close($con);
      die('{"type":"error","msg":"用户名重名"}');
  }

  # 没有重复数据 : 
  $insert_sql = "INSERT INTO `user` ( `email` , `password`) VALUES ('$email' , '$password')";

  // 执行sql语句
  $res = mysql_query($insert_sql);
  
  # 根据 $res 判定插入是否成功;
  if($res){
      echo '{"type":"success","msg":"注册成功"}';
  }else{
      echo '{"type":"error","msg":"数据库错误"}';
  }

?>

用到的封装函数如下

/* *
 * formateUrl : 序列化 GET请求的 URL;
 *   
 * formateUrl( url路径 | string , data 数据 | object );
 * 
 * @return url | string ;
 * 
 * */

function formateUrl(url, data) {
  var start = true;
  for (var key in data) {
    url += (start ? "?" : "&") + key + "=" + data[key];
    start = false;
  }
  return url;
}

/* *
 * formateUrl : 序列化 GET请求的 URL;
 *   
 * formateUrl( [ url | string ] , data | object );
 *   
 * @return 
 * 
 * 1. key=value;
 * 2. url?key=value;
 * 
 * */

function formate(url, data) {
  var type = "GET";
  if (typeof url === "object" && !(url instanceof Array)) {
    data = url;
    type = "POST";
    url = "";
  }
  var start = true;
  for (var key in data) {
    if (type === "GET") {
      url += (start ? "?" : "&") + key + "=" + data[key];
    } else {
      url += (start ? "" : "&") + key + "=" + data[key];
    }
    start = false;
  }
  return url;
}

/* *
 * ajax : 发送ajax请求 注意和 promise 一起使用
 *   
 * ajax( method | string  , url | string  , callback | function , data | object );
 *   
 * @return xhr 
 * 
 * */
function ajax(options) {
  return new Promise(function (resolve, reject) {
    // 参数优化为了啥?
    // 增加默认参数;
    // 对象合并;
    options = Object.assign({
      method: "GET",
      callback: function () {},
      url: "",
      data: {},
      // jsonp形式的回调函数名
      jsonpcallback: "callback"
    }, options);

    if (options.method === "jsonp") {
      // 请求发送;
      var script = document.createElement("script");
      options.data.jsonpcallback = options.data.jsonpcallback ? options.data.jsonpcallback : "callback"
      script.src = formate(options.url, options.data);
      document.body.appendChild(script);
      window[options.data.jsonpcallback] = function (data) {
        options.callback(data);
        resolve(data);
      }
      script.onload = function () {
        script.remove();
      }
    } else {
      var xhr = new XMLHttpRequest();
      xhr.open(options.method, options.method.toUpperCase() === "GET" ? formate(options.url, options.data) : options.url);
      if (options.method.toUpperCase() === "POST") {
        xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
      }
      xhr.send(options.method.toUpperCase() === "POST" ? formate(options.data) : null);
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && /^2\d{2}/.test(xhr.status)) {
          options.callback(xhr.responseText)
          resolve(xhr.responseText)
        }
      }
    }
  })
}

// 封装获取元素函数
function $(selector) {
  return document.querySelector(selector);
}

// 封装 设置cookie
function setCookie(name, value, expires) {
  // 核心 : 操作字符串 !;
  var cookie_str = name + "=" + value;
  //判定是否有必要增加过期时间;
  if (typeof expires === "number") {
    var d = new Date();
    d.setDate(d.getDate() + expires);
    cookie_str += ";expires=" + d;
  }
  // 把拼接好的字符串设置到 document.cookie 上;
  // console.log(cookie_str);
  document.cookie = cookie_str;
}

// 封装 获取cookie;
function getCookie(name) {
  // 分割;
  // 一定要以分号加空格的间隔进行分割;
  var cookie_arr = document.cookie.split("; ");
  for (var i = 0; i < cookie_arr.length; i++) {
    // 每一条cookie => key=value;
    var cookie_item = cookie_arr[i]
    // console.log(cookie_item);
    cookie_item = cookie_item.split("=");
    if (cookie_item[0] == name) {
      return cookie_item[1];
    }
  }
  return "";
}

// 封装删除 cookie ;
function removeCookie(name) {
  setCookie(name, "", -1);
}

效果图如下

顺便看下数据库数据

引入说明:
1、文中搜索框的下拉菜单引用百度数据接口,这里感谢百度支持
2、文中布局引用bootstrap 里面布局,感谢bootstrap的支持

本文地址:https://blog.csdn.net/weixin_42681295/article/details/107366673

《登录登出页面的跳转和模糊搜索实现.doc》

下载本文的Word格式文档,以方便收藏与打印。