做决定之前仔细考虑,一旦作了决定就要勇往直前、坚持到底!
【1 ikunGG邮箱注册
】
整个流程展示:
1.文件目录
2.页面效果展示及代码
- mysql数据库中的初始表
2.1 主页 09.html
:里面代码部分解释
display: inline-block;
让块元素h1变成行内块元素,不然块级元素h1的宽度会撑满父元素宽度
box-sizing: border-box;
盒子的大小:盒子大小固定,与margin,padding,border无关,但会自动调节content的大小
position: absolute;
绝对定位会使元素脱离文档流 ,绝对定位元素 是根据 离其(自身)最近并且**
有定位
设置(static定位除外)的父元素
** 作为 定位位置的参考起点
cursor:text
大写I的点击填写
z-index: 999;
参数越大,表示越会显示在其他堆叠元素之上。Z-index 仅能在定位元素上有效(例如 position:absolute;)
display: none;
该元素不显示 ,相当于html标签里面没有这个元素盒子了
letter-spacing:
属性增加或减少字符之间的空白(字符间距)
- 如果label标签设置了for=“xxx”,input标签设置了id=“xxx”【
xxx一样
】,那么,label标签简单理解为可以绑定表单元素。label本身与某个表单绑定,当用户点击了label标签则会触发表单,也就相当于点击了表单。
<!-- label标签是行内元素 --> <label for="emailadd">邮箱地址</label> <input type="text" class='username' name="username" id="emailadd">
previousSibling
返回当前元素上一个兄弟元素节点【请点击此处】
- 下面代码打印
i
时,全部都是3,最后一个。???为什么会出现这样的情况???
console.log(window); for (var i = 0; i < inputs.length; i++) { // 聚焦时 inputs[i].onfocus = function () { // 当聚焦的时候让label消失 console.log(i);//全部是3 console.log(this); // this => 触发聚焦这个事件的input元素 } }
解答:
原因就是:js事件处理器在线程空闲时间不会运行,导致最后运行的时候输出的都是i最后的值。在每个点击事件函数的作用域链中都保存着windows的活动对象**(for语句不构成作用域),所以它们引用的是同一个变量i,即i属于一个全局变量**,所以在给每个li绑定事件后,每个函数内部i的值都是3。
【意思就是说:外面的for循环已经执行完了,i已经是3了,再等你点击绑定的事件时,打印的i可不就是3了吗?】
通俗点来说就是:先给每个li绑定点击事件,绑定完点击事件后,每次没有被执行罢了。执行的时候已经被赋值成3了,(同步执行,异步执行问题)i是一个全局变量,所以再点击某个li输出i的时候,输出的自然是3了。
解决问题:使用ES6中Let完美解决。var i = 0 —> let i = 0
我们不点击input框,直接我们打印一下window对象身上有没有i。
<!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.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
background: #eff8ff;
}
/* 整个最外层包裹的盒子的样式 */
.container {
width: 470px;
/* 内边距10px */
padding: 10px;
border: 1px solid #333;
/* 上下30px,左右自动居中对齐 */
margin: 30px auto;
}
.container h1 {
/* 让块元素h1变成行内块元素,不然块级元素h1的宽度会撑满父元素宽度 */
display: inline-block;
font-size: 30px;
/* 字体粗细层度 */
font-weight: 400;
color: #333;
/* h1字号:原本32px = 2rem=2*16px */
line-height: 34px;
}
/* 父级元素container里的所有item子元素 */
.container .item {
width: 470px;
/* 距离上面同级元素底边的距离 */
margin-top: 35px;
/* 定位 */
position: relative;
}
.container .item input {
width: 100%;
height: 46px;
/* 盒子的大小:盒子大小固定,与margin,padding,border无关,但会自动调节content的大小 */
box-sizing: border-box;
border: 1px solid #cbcbcb;
border-radius: 5px;
/* 上11 右0 下10 左16 */
padding: 11px 0 10px 16px;
font-size: 16px;
}
.container .item label {
height: 46px;
box-sizing: border-box;
border-radius: 3px;
padding: 14px 0 10px 17px;
font-size: 16px;
/* 绝对定位会使元素脱离文档流 */
/* 绝对定位元素 是根据 离其(自身)最近并且有定位设置(static定位除外)的父元素 作为 定位位置的参考起点 */
position: absolute;
top: 0;
left: 0;
color: #bfbfbf;
/* cursor:text(大写I的点击填写) */
cursor: text;
/* 参数越大,表示越会显示在其他堆叠元素之上。Z-index 仅能在定位元素上有效(例如 position:absolute;) */
z-index: 999;
}
.container .item .username {
/* 距离右边父级元素120px */
padding-right: 120px;
}
.container .item .domain {
width: 131px;
color: #343434;
/* 绝对定位会使元素脱离文档流 */
position: absolute;
top: 0;
right: 0;
border: none;
height: 46px;
/* 盒子的大小:盒子大小固定,与margin,padding,border无关,但会自动调节content的大小 */
box-sizing: border-box;
border-radius: 3px;
padding: 11px 0 10px 16px;
font-size: 16px;
line-height: 25px;
}
.tip {
height: 17px;
line-height: 17px;
/* 上面两行代码,是内容垂直居中对齐 */
font-size: 13px;
color: #9e9e9e;
/* 该元素不显示 */
display: none;
margin-top: 10px;
}
#error {
color: #ff5b5b;
font-size: 12px;
display: none;
font-size: 13px;
margin-top: 10px;
}
#success {
color: #33a853;
font-size: 12px;
display: none;
font-size: 13px;
margin-top: 10px;
}
.btn {
color: #fff;
background: #3b78dd;
font-size: 22px;
letter-spacing: 2.2px;
/* 该元素盒子被内容,line-height撑高 */
line-height: 46px;
/* display:block就是将元素显示为块级元素 */
display: block;
text-align: center;
border-radius: 5px;
margin-top: 35px;
}
</style>
</head>
<body>
<div class="container">
<h1>欢迎注册ikunGG邮箱</h1>
<div class="item">
<!-- label标签简单理解为可以绑定表单元素。label本身与某个表单绑定,当用户点击了label标签则会触发表单,也就相当于点击了表单 -->
<!-- label标签是行内元素 -->
<label for="emailadd">邮箱地址</label>
<input type="text" class='username' name="username" id="emailadd">
<p class="tip">6~18个字符,可使用字母、数字、下划线,需要以字母开头</p>
<div class="domain">
164.com
</div>
<p id="error">
该邮箱已经被注册
</p>
<p id="success">恭喜,该邮件地址可以注册</p>
</div>
<div class="item">
<label>密码</label>
<input type="text" name="password">
<p class="tip">6~16个字符,区分大小写</p>
</div>
<div class="item">
<label>手机号</label>
<input type="text" name="phone">
<p class="tip">可通过该手机号找回密码</p>
</div>
<div class="btn" id="btn">立即注册</div>
</div>
<!-- 引入封装好的Ajax技术 -->
<script src="js/ajax.js"></script>
<script>
// 获取所有的input框
var inputs = document.getElementsByTagName("input");
var username = document.getElementsByClassName("username")[0];
var successTip = document.getElementById("success");
var errorTip = document.getElementById("error");
var btn = document.getElementById("btn");
// 记录存储名称
var keys = {
"username": "邮箱地址",
"password": "密码",
"phone": "手机号"
}
// 设置一个状态,用来判断当前的邮箱地址是否已经被注册了,如果被注册了,就不允许提交
var emailFlag = true;
// console.log(window);
for (var i = 0; i < inputs.length; i++) {
// 聚焦时
inputs[i].onfocus = function ()
{
// 当聚焦的时候让label消失
// console.log(i);//全部是3
// console.log(this);
// console.log(this.previousSibling.previousSibling);//label
// this => 触发这个事件的input元素
// previousSibling 返回当前元素上一个兄弟元素节点【重点补充】
// previousSibling和nextSibling是获取上一个、下一个同胞元素,如果上一个或下一个同级节不存在,则此属性返回值是null
// this.previousSibling.previousSibling.style.display = 'none'
// 和上面代码一样,但下面的代码兼容性不行
this.previousElementSibling.style.display = "none";
// 当聚焦的时候让下面的提示文案显示
// this.nextSibling.nextSibling.style.display = "block";
this.nextElementSibling.style.display = "block";
// 如果input的name属性为username,即,如果聚焦的为第一个input框,那么让成功和失败的提示消失
if (this.name == 'username') {
// 强制让成功和失败的提示消失
successTip.style.display = "none";
errorTip.style.display = "none";
}
}
// 失去焦点
inputs[i].onblur = function ()
{
// 当失去焦点的时候,判断,如果有value值,就不让label显示,否则就显示label
if (!this.value) {
this.previousSibling.previousSibling.style.display = 'block'
}
// 失去焦点的时候让下面的提示文案隐藏
this.nextSibling.nextSibling.style.display = "none";
// 如果是用户名则发送ajax请求去判断当前的用户是否已经被注册
// 找到用户名这个框且不能为空,才能校验
if (this.name == "username" && this.value) {
// 发送Ajax请求校验
validate(this.value);
}
}
}
// 校验请求
function validate (value)
{
// 可以直接调用封装好的
ajax.get("check.php", { "username": value }, function (data)
{
// 返回的数据时SUCCESS,那么就是可以注册email
if (data == "SUCCESS") {
// 显示成功提示
successTip.style.display = "block";
// 邮箱的可提交状态为true
emailFlag = true;
} else if (data == "ERROR") {
//显示失败提示
errorTip.style.display = "block";
// 邮箱的可提交状态为false,即不可提交
emailFlag = false;
}
})
}
// 发送请求提交数据
btn.onclick = function ()
{
// 第一步:要先判断用户名是否可以使用,如果不可以抛出错误
// emailFlag 不可以注册是 true
if (!emailFlag) {
alert("当前用户名已经被占用,请输入新的邮箱地址")
return;
}
// 提交参数
var subObj = {};
// 第二步:判断所有的表单信息是否都填上了,如果没有就抛出错误提示
for (let i = 0; i < inputs.length; i++) {
// inputs[i].value :不为空,就是真
if (!inputs[i].value) {
return;
alert("请完善" + keys[inputs[i].name]);
} else {
// 表单信息赋值,相当于以k-v的形式存进空白对象subObj中
subObj[inputs[i].name] = inputs[i].value;
}
}
// 如果都没有被return就将所有的信息提交到数据库
add(subObj);
}
// 发送请求
function add (json)
{
// 提交逻辑
ajax.post("add.php", json, function (data)
{
// 注册成功后,那么emailFlag状态变为false,即不可注册
if (data == "SUCCESS") {
alert("提交成功")
emailFlag = false;
} else {
alert("提交失败!请重试")
}
})
}
</script>
</body>
</html>
2.2 add.php
<?php
// 从客户端传递过来的数据,
// 得到邮箱地址,密码和手机号,并存在变量中
$username= $_POST["username"];
$phone= $_POST["phone"];
$password= $_POST["password"];
// 链接数据库
$connect = mysql_connect("localhost",'root','xjf123456');
// 选择数据库
mysql_select_db("ikungg");
// 设置字符集
mysql_query("SET NAMES UTF8");
// 插入SQL
$sql = "INSERT INTO email_form (username,password,phone) VALUES ('{$username}','{$password}','{$phone}')";
// 执行SQL,存进数据库了
$result = mysql_query($sql);
// 如果$result返回1了,就说明提交成功了,服务器操作数据库,并返回数据 SUCCESS 或者 ERROR
if($result == 1) {
echo "SUCCESS";
} else {
echo "ERROR";
}
?>
2.3 check.php
<?php
// 得到邮箱地址
$username= $_GET["username"];
// 链接数据库
$connect = mysql_connect("localhost",'root','xjf123456');
// 选择数据库
mysql_select_db("ikungg");
// 设置字符集
mysql_query("SET NAMES UTF8");
// 查询SQL
$sql = "SELECT * FROM email_form WHERE username = '{$username}'";
// 执行SQL
$result = mysql_query($sql);
// 返回查询出来的结果数量 ,符合条件的数据有多少行
$num = mysql_num_rows($result);
// 当前的结果如果大于0就说明有查询结果
if($num > 0) {
echo "ERROR";
} else {
echo "SUCCESS";
}
?>
2.4 ajax.js
(function(){
// 唯一暴露的参数变量
// 把ajax空对象放到Windows上
window.ajax = ajax = {};
function common(xhr,JSON,callback) {
// 如果用户只传了两个参数,第二个参数如果不是JSON就是函数
// 如果第二个参数的类型是函数了,说明第二个参数就是回调函数
if(typeof JSON == "function") {
// 如果第二个参数是回调函数了,让callback参数就等于这个函数
callback = JSON;
JSON = {};
}
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
callback(xhr.responseText)
}
}
}
// 拼接JSON数据,比如我们的参数{"id":10001,"name":"小明","age":18}
// 转换为id=10001&name=小明&age=18
var temp = [];
for(var k in JSON) {
temp.push(k+"="+encodeURI(JSON[k]));
}
// 将temp的数据转换为字符串格式的,共最后提交请求使用
return temp.join("&");
}
ajax.get = function(url,JSON,callback) {
var xhr = new XMLHttpRequest();
// 调用公共方法
var str = common(xhr,JSON,callback)
// 防止没有参数
if(str) {
url+="?"+str
}
xhr.open("get",url,true);
xhr.send(null);
}
ajax.post = function(url,JSON,callback) {
var xhr = new XMLHttpRequest();
// 调用公共方法
var str = common(xhr,JSON,callback)
xhr.open("post",url,true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(str)
}
})()