登录登出页面的跳转

    • 首页 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.googleapis.com/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