您的位置:首页 > 科技 > 能源 > day19JS-AJAX数据通信

day19JS-AJAX数据通信

2024/10/6 10:58:09 来源:https://blog.csdn.net/kwj258036/article/details/141926207  浏览:    关键词:day19JS-AJAX数据通信

1. 什么是AJAX

        原生生js中有两种通信,一个ajax,还有一个是fetch

        AJAX 并不是编程语言,是一种从网页访问 Web 服务器的技术AJAX 代表异步 JavaScript 和 XML

        AJAX 使用浏览器内建的 XMLHttpRequest 对象从 web 服务器请求数据,在使用JavaScriptHTML DOM来显示或使用数据。Ajax 允许通过与场景后面的 Web 服务器交换数据来异步更新网页。这意味着可以更新网页的部分,而不需要重新加载整个页面

2. AJAX如何工作?

  1. 网页中发生一个事件(页面加载、按钮点击)。
  2. 由 JavaScript 创建 XMLHttpRequest 对象
  3. XMLHttpRequest 对象向 web 服务器发送HttpRequest请求
  4. 服务器处理HttpRequest请求
  5. 服务器将响应发送回网页
  6. 由 JavaScript 读取响应
  7. 由 JavaScript 更新页面

3. XMLHttpRequest 对象详解

        XMLHttpRequest 对象用于与服务器交互数据。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据

3.1 AJAX使用步骤

        所有现代浏览器都支持XMLHttpRequest 对象。XMLHttpRequest 对象可用于在后台与 Web 服务器交换数据。这意味着可以更新网页的部分内容,而无需重新加载整个页面。

1. 创建 XMLHttpRequest 对象的语法:

var 实例化对象名 = new XMLHttpRequest();

var xhr = new XMLHttpRequest();

2. 定义回调函数。回调函数是作为参数传递给另一个函数的函数。在这种情况下,回调函数应包含响应准备就绪时要执行的代码

xhr.onload = function() {// 当响应准备就绪时要做什么
}

3. 发送请求。向服务器发送请求,使用 XMLHttpRequest 对象的 open() 和 send() 方法。

案例:

xhr.open("GET", "http://localhost:4000");
xhr.send();

3.2 跨域访问(Access Across Domains)

出于安全原因,现代浏览器一般不允许跨域访问。但是可以使用跨域的,可以把跨域写入响应头中。

跨域访问书写语法:响应对象.writeHead(响应码,{跨域设置})

案例:

// 引入http
const http = require("http");
// 创建一个服务对象,req:请求对象, res:响应对象
http.createServer(function (req, res) {// 编写响应头,200时成功码,res.writeHead(200, {"Access-Control-Allow-Origin": "*"})res.end("a");
}).listen(process.env.PORT);//侦听来访问该端口的请求

 "Access-Control-Allow-Origin":"*" :响应标头指定了该响应的资源是否被允许与给定的来源(origin)共享。

 "Access-Control-Allow-Methods":"*" :允许所有方法跨域

 "Access-Control-Allow-Headers":"*" :允许所有标头跨域。

3.3 XMLHttpRequest 对象的属性

属性描述
onload定义接收到(加载)请求时调用的函数。使用 XMLHttpRequest 对象时,可以定义一个回调函数,以便在请求收到答复时执行。
onreadystatechange定义当 readyState 属性发生变化时调用的函数
readyState

保存 XMLHttpRequest 的状态。每当readyState 发生变化时就会调用 onreadystatechange 函数。

  • 0:创建ajax并实例化对象。
  • 1:服务器连接已建立(open打开),并且发送请求头。
  • 2:send发送消息体,并且请求对象已收到响应头。
  • 3:接收服务端发送的消息,正在接收处理请求。
  • 4:接收服务端发送数据完成,并且响应已就绪。
responseText

服务器响应属性,字符串形式返回响应数据。

responseXML服务器响应属性,XML 数据返回响应数据。
status

返回请求的状态号

  • 200: "OK"
  • 403: "Forbidden"
  • 404: "Not Found"
statusText返回状态文本(比如 "OK" 或 "Not Found")

3.4 XMLHttpRequest 对象的方法

方法名描述
new XMLHttpRequest()创建新的 XMLHttpRequest 对象
abort()取消当前请求
getAllResponseHeaders()

服务器响应方法,从服务器返回所有头部信息

getResponseHeader()服务器响应方法,从服务器返回特定的头部信息
open(method, url, async, user, password)

设置请求访问服务器的各种参数。

参数:

  • method请求类型 GET 或 POST。Method使用GET时,URL可以是本地路径,可以是网络路径http和https。
  • url被访问服务器的url (http://+ip+端口号)。
  • async是否异步。true(异步)或 false(同步)。如需异步发送请求,open() 方法的 async参数必须设置为 true如果是false同步就不属于使用侦听事件了。
  • user:可选的用户名。
  • password:可选的密码。
send()

向服务器发送请求的方法。该方法无参数用于 GET 请求

send(string)是向服务器发送请求的方法。该方法有参数用于 POST 请求
setRequestHeader(header,value)

向请求添加 HTTP 头部。将标签/值对添加到要发送的标头。

参数:

  • header 规定头部名称。
  • value 规定头部值。

3.4.1 open()方法中的参数method请求类型详解

  1.  GET
  2.  POST:主要用于向服务端发送消息,发送的内容通过send发送,可以发送文本、二进制流、大二进制流(Blob)、FormData、文档。可以接收消息,不会调用缓存,POST发送时同域情况下会携带cookie,跨域时需要主动携带cookie。POST是先发起请求头,然后再发起消息体。
  3. PUT:目的是表意,向服务器添加数据,和post作用相同。
  4. DELETE:目的是表意,向服务器提交删除数据,和post作用相同。
  5. OPTIONS :在使用POST、PUT、DELETE跨域时都会触发。

使用非GET和POST,跨域需要服务器同意,因为Method也需要处理跨域。

3.4.2 请求头和响应头 

1. 请求头的注意事项:

  • 请求头必须写在open之后,send之前。使用setRequestHeader()方法设置请求头。
  • 请求头写法单词首字母大写,单词直接使用-分割,如果是自定义请求头使用X-开头
  • 例如:setRequestHeader("Content-Type","application/json")这行代码的作用是告诉服务器发送的请求体中包含的是 JSON 格式的数据,这样服务器才能正确地解析这些数据。

2. 请求标头中的属性重点详解Content-Type:

        Content-Type指定请求体的内容类型,用于告知服务器请求体的数据类型(如表单数据、JSON数据等)。

Content-Type的属性值可以是以下类型:

  • text/plain:纯文本类型,不包含任何格式控制字符,通常用于传输普通文本数据。
  • text/html:HTML文档类型,用于传输HTML格式的网页内容。
  • application/json:JSON数据类型,用于传输结构化的JSON数据。
  • application/xml:XML数据类型,用于传输结构化的XML数据。
  • multipart/form-data:用于通过HTTP POST方法传输表单数据,支持传输文件和文本数据,常用于文件上传。
  • application/x-www-form-urlencoded:用于通过HTTP POST方法传输表单数据,将表单字段以URL编码的形式包含在请求体中。
  • image/jpegimage/pngimage/gif:图片类型,用于传输图片文件的内容。
  • application/octet-stream:二进制数据流类型,表示不属于其他已知类型的任意二进制数据,例如传输文件时常用的类型。

其它属性如图所示: 

3. 响应头的注意事项:

  • 获取所有的响应头使用getAllResponseHeaders()方法。

属性如图所示: 

4. timeout超时

        timeout是一个无符号长整型数,代表着一个请求在被自动终止前所消耗的毫秒数。默认值为 0,意味着没有超时

案列:

    // timeout超时var xhr = new XMLHttpRequest();xhr.addEventListener("load", loadHandler);xhr.addEventListener("timeout", timeoutHandler);xhr.open("PUT", "http://localhost:4000");xhr.timeout = 1;//如果1毫秒之后服务器还没有返回数据就算超时xhr.send();function loadHandler(e) {console.log(xhr.response);}function timeoutHandler(e) {// console.log(e);xhr.abort();//断开xhr// 断开后重新调用ajax,3次}

超时过后会得到一个 ProgressEvent事件

解决超时的方法:使用abort();断开请求,断开后重新调用ajax3次

5. 服务器使用AJAX的案例

5.1 最简单的前端AJAX通信

1. 创建server文件夹。

2. 在集成终端中执行npm init -y 初始得到package.json文件。

3. 编写package.json文件。

{"name": "serverzixie","version": "1.0.0","main": "server.js","scripts": {"start": "cross-env PORT=4000 nodemon"},"keywords": [],"author": "","license": "ISC","devDependencies": {"nodemon": "^3.1.4","cross-env": "^7.0.3"}
}

4.在集成终端中执行npm i 。

5. 编写server文件并在集成终端中使用npm start启动服务。

// 引入http
const http = require("http");
// 创建一个服务对象,req:请求对象, res:响应对象
http.createServer(function (req, res) {// 编写响应头,200时成功码,res.writeHead(200, {"Access-Control-Allow-Origin": "*"})res.end("a");
}).listen(process.env.PORT);//侦听来访问该端口的请求

6.  编写前端发送请求的html文件。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title>
</head><body><script>// 创建一个var xhr = new XMLHttpRequest();xhr.addEventListener("load", loadHandler);xhr.open("GET", "http://localhost:4000");xhr.send();function loadHandler(e) {console.log(xhr.response);}</script>
</body>
</html>

 7. 查看效果。

5.2  服务器使用AJAX与数据库通信

在5.1 代码的基础上继续编写代码

1. 在server文件夹新创建一个MYSQL.js的文件。

2. 重新编写package.json文件。

{"name": "serverzixie","version": "1.0.0","main": "server.js","scripts": {"start": "cross-env PORT=4000 nodemon"},"keywords": [],"author": "","license": "ISC","dependencies": {"mysql": "^2.18.1", //自己的mysql是低版本使用mysql 2.18.1"mysql2": "^3.11.0" ///自己的mysql是高版本使用mysql2 3.11.0},"devDependencies": {"nodemon": "^3.1.4","cross-env": "^7.0.3"}
}

3.在集成终端中执行npm i 。 

4. 编写MYSQL.js文件。

// 引入MySQL文件
const mysql = require("mysql");
// 创建一个连接
const connect = mysql.createConnection({host: "localhost",//IP地址port: 3306, //端口号database: "mysql_js",//连接的数据库名user: "root",//数据库用户名password: "123456" //数据库密码
})
console.log(connect);

5. 在 server.js中引入数据库。并使用 npm start命令开启服务。

// 引入数据库js文件
require("./MYSQL");
// 引入http
const http = require("http");
// 创建一个服务对象,req:请求对象, res:响应对象
http.createServer(function (req, res) {// 编写响应头,200时成功码,res.writeHead(200, {"Access-Control-Allow-Origin": "*"})res.end("a");
}).listen(process.env.PORT);//侦听来访问该端口的请求

 没有报红说明连接数据库成功

6. 历史记录的相关知识

历史记录分为两种:hash历史记录 和 history历史记录

6.1 hash历史记录

hash历史记录hash 不会刷新页面,但是会触发后产生历史记录历史记录回退时hash也会回退到上一次历史记录的hash值如果刷新页面hash历史记录就会没有了,因为刷新页面会重新初始化页面。

  • 访问地址#后面的内容发生改变时就是hash在发生改变
  • hashchange :是一个hash事件,可以用来侦听hash值的变化。

案例:点击哪个下面的方框里就显示哪个。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>ul {list-style: none;display: flex;}li {width: 160px;height: 30px;border: 1px solid #000;}li>a {text-decoration: none;display: block;width: 100%;height: 100%;text-align: center;line-height: 30px;color: #000;border-left: none;}li>a>:first-child {border-left: 1px solid #000;}.content {width: 1400px;height: 500px;border: 1px solid #000;}</style>
</head><body><ul><li><a href="#vegetable">蔬菜</a></li><li><a href="#fruits">水果</a></li><li><a href="#meat">肉禽</a></li><li><a href="#oil">米油</a></li></ul><div class="content"></div><script>let list = {vegetable: ["白菜", "菠菜", "胡萝卜", "油麦菜", "娃娃菜"],fruits: ["苹果", "香蕉", "西瓜", "桃子", "榴莲"],meat: ["猪肉", "牛肉", "羊肉", "鸡肉", "鸭肉"],oil: ["菜籽油", "橄榄油", "花生油", "大米", "小米"]}// hash 不会刷新页面,但是会触发后产生历史记录var content;init();function init() {// 获取content选择器content = document.querySelector(".content");// 侦听hash事件window.addEventListener("hashchange", hashChangeHandler);//location.hash :获取到本地的hash // 点击哪个li便签就会获取a标签href属性的值console.log(location.hash);//例如在页面中点击蔬菜就会得到#vegetable// 有hash历史记录时的情况if (location.hash) {// 调用侦听的函数hashChangeHandler();// 没有有hash历史记录时的情况} else {location.href += "#vegetable"}}// 侦听的函数function hashChangeHandler(e) {// 获取到的hash包括#,使用slice方法获取到#后面的内容let name = location.hash.slice(1);// 把点击对应的内容写入到div盒子中content.innerHTML = list[name];}</script>
</body></html>

点击

 

 

 历史记录回退:

6.2 history历史记录

  • history.back() : 回退
  • history.forward() :前进
  • history.go(1) :刷新
  • history.pushState(数据,无用的标识,url(可以添加hash或者search)) :参数数据不能是DOM对象,可以是字符串或者对象、数组。当使用pushState后,会向历史栈中添加一个历史数据,在使用popstate事件后,可以在不同历史中拿到这个数据。

  • history.replaceState(数据,无用的标识,url(可以添加hash或者search)) :替换历史数据。

案例:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>ul {list-style: none;display: flex;}li {width: 160px;height: 30px;border: 1px solid #000;border-left: none;text-align: center;line-height: 30px;}li:first-child {border-left: 1px solid #000;}.content {width: 1400px;height: 500px;border: 1px solid #000;}</style>
</head><body><ul><li id="vegetable">蔬菜</li><li id="fruits">水果</li><li id="meat">肉禽</li><li id="oil">米油</li></ul><div class="content"></div><script>let list = {vegetable: ["白菜", "菠菜", "胡萝卜", "油麦菜", "娃娃菜"],fruits: ["苹果", "香蕉", "西瓜", "桃子", "榴莲"],meat: ["猪肉", "牛肉", "羊肉", "鸡肉", "鸭肉"],oil: ["菜籽油", "橄榄油", "花生油", "大米", "小米"],};let ul, content;init();function init() {// 获取ulul = document.querySelector("ul");// 获取content选择器content = document.querySelector(".content");// 给ul添加侦听事件ul.addEventListener("click", clickHandler);// 当历史发生改变时(点击了前进或者回退按钮时触发)window.addEventListener("popstate", popStateHandler);if (!history.state) {history.replaceState("vegetable", "vegetable")}popStateHandler();}function clickHandler(e) {// 如果不是li,return结束if (e.target.nodeName !== "LI") return;// 向div盒子中写入被点击对象的内容content.innerHTML = list[e.target.id];// 向历史栈中添加一个历史数据history.pushState(e.target.id, e.target.id)}function popStateHandler(e) {// 获取当前的历史数据// console.log(history.state);content.innerHTML = list[history.state];}</script>
</body></html>

7. 编写服务器与客户端通信案例

7.1 注册功能、注册页面切换到登录页面

1. 创建一个template的文件夹,里面有list.js、login.js、register.js、index.html文件。

2. 再创建一个js文件夹,里面有ajax.js文件。

3.  编写ajax.js文件。

export default class AJAX {// IP地址static URL = "169.254.28.173";// 端口号static PORT = 4003;// 使用的协议static PROTOCOL = "http://";// post请求static POST = "post";// get请求static GET = "get";constructor() {}// 处理get请求的方法// 参数 router:对应接口路由,query:访问地址?号后面的内容, headers:请求头static async get(router, query = {}, headers = {}) {// 调用将对象转换为字符串的方法query = AJAX.queryStringify(query);// 判断路由的第一位是不是/,字符串的方法startWith接收判断字符串的第一个字符是否是某个字符// 不是的情况,就拼接上/if (!router.startsWith("/")) router = "/" + router;// 是的情况,拼接url。如果query没有传参则传一个空对象let url = AJAX.PROTOCOL + AJAX.URL + ":" + AJAX.PORT + router + (query.trim().length === 0 ? "" : "?" + query);// 查看一下url的拼接情况// console.log(url);//测试4// 调用ajax的方法发送请求return await AJAX.ajax(url, AJAX.GET, headers);}// 处理post请求的方法// 参数 router:对应接口路由,body:请求传输过来的数据,headers:请求头static async post(router, body = {}, headers = {}) {// 判断路由的第一位是不是/,字符串的方法startWith接收判断字符串的第一个字符是否是某个字符// 不是的情况,就拼接上/if (!router.startsWith("/")) router = "/" + router;// 是的情况,拼接url。如果query没有传参则传一个空对象let url = AJAX.PROTOCOL + AJAX.URL + ":" + AJAX.PORT + router;// 调用ajax的方法发送请求return await AJAX.ajax(url, AJAX.GET, headers, body);}//上面的get、post方法调用ajax// 参数 url:请求路由,method:用于判断是上面方法, headers:请求头, body:请求传输过来的数据static ajax(url, method, headers, body) {return new Promise(function (resolve, reject) {// XMLHttpRequest 对象可用于在后台与 Web 服务器交换数据。var xhr = new XMLHttpRequest();// 规定请求xhr.open(method, url);for (var key in headers) {// 设置发送的标头xhr.setRequestHeader(key, headers[key]);}// 如果是get请求直接发送,如果是post请求把将 JavaScript 对象转换为字符串。method === AJAX.GET ? xhr.send() : xhr.send(JSON.stringify(body));xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status < 300 && xhr.status >= 200) {let headers = AJAX.getHeaders(xhr)if (headers["content-type"]?.trim() === "text/html;charset=utf-8") {resolve(xhr.response)} else {let data;try {data = JSON.parse(xhr.response)} catch (e) {data = AJAX.getQuery(xhr.response)}resolve({ data, headers });}} else if (xhr.readyState === 4) {reject(xhr.status);}}})}// url传参是对象就将对象转换为字符串的方法。static queryStringify(query) {// 如果query是字符串直接返回queryif (typeof query === "string") return query;// 如果query不是字符串先进行遍历let str = "";for (var key in query) {// 判断遍历的每一个元素是否是数组,这里是数组的情况if (Array.isArray(query[key])) {str += "&" + query[key].map(function (item) {// 打印一下查看效果// console.log(key, item);// 返回结果return key + "=" + item;}).join("&")// 测试1:打印查看字符串是否拼接成功// console.log(str);// query中的元素是一个对象的情况} else if (typeof query[key] === "object") {// 将对象解析成Json字符串str += "&" + key + "=" + JSON.stringify(query[key]);// 其它情况 } else {str += "&" + key + "=" + query[key];}}//去掉字符串第一个&符号str = str.slice(1);// 测试2、3:打印查看一下字符串// console.log(str);return str;}// 请求头static getHeaders(xhr) {return xhr.getAllResponseHeaders().split(/\n/).reduce((value, item) => {if (item.trim().length === 0) return value;let arr = item.trim().replace(/\r/, "").split(":");try {value[arr[0]] = JSON.parse(arr[1])} catch (e) {value[arr[0]] = arr[1];}return value}, {})}static getQuery(str) {if (!/.*?=.*?/.test(str)) return str;return str.split("&").reduce((value, item) => {let arr = item.split("=");try {value[arr[0]] = JSON.parse(arr[1])} catch (e) {value[arr[0]] = arr[1];}return value}, {})}
}

4. 在index.html文件中编写测试ajax.js的代码。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><script type="module">import AJAX from "./js/ajax.js";// AJAX.queryStringify({ a: [1, 2, 3] });//测试1// AJAX.queryStringify({ a: [1, 2, 3], b: { a: 1, b: 2 } });//测试2// AJAX.queryStringify({ a: [1, 2, 3], b: { a: 1, b: 2 }, c: 3, d: 4 });//测试3//测试4 ==> http://169.254.28.173:4003/login?a=1&b=2// AJAX.get("/login", { a: 1, b: 2 });//测试4 ==> http://169.254.28.173:4003/loginAJAX.get("/login");</script>
</body></html>

5. 在集成终端中下载jquery和bootstrap@3

执行命名:

npm i jquery

npm i bootstrap@3

6. 整理项目结构。

  •  把node_modules --> jquery  --> dist --> jquery.js移动到js文件夹下。
  • 把node_modules --> bootstrap--> dist --> js -->bootstrap.js 移动到js文件夹下。
  • 把node_modules --> bootstrap--> fonts文件夹 移动到最外层文件夹下。template
  • 在新建一个css文件夹,node_modules --> bootstrap--> css --> bootstrap.css 移动到新建的css文件夹
  • 拉完以后把node_modules文件夹删掉,把package-lock.json和package.json也删掉

项目结构如下:

 7. 在js文件夹中新创建并编写VerifyForm.js表单验证类

// 验证表单是否合法的类
export default class VerifyForm {static setForm(elem) {// 根据表单验证的结果添加样式if (VerifyForm.verify(elem.name, elem.value)) {// 从元素的父元素的选择器集合中移除has-error类选择器elem.parentElement.classList.remove("has-error")// 向元素的下一个兄弟元素的选择器集合中删除glyphicon-remove类选择器elem.nextElementSibling.classList.remove("glyphicon-remove")// 向元素的父元素的选择器集合中添加has-success类选择器elem.parentElement.classList.add("has-success")// 向元素的下一个兄弟元素的选择器集合中添加glyphicon-ok类选择器elem.nextElementSibling.classList.add("glyphicon-ok")} else {// 从元素的父元素的选择器集合中移除has-success类选择器elem.parentElement.classList.remove("has-success")// 向元素的下一个兄弟元素的选择器集合中删除glyphicon-ok类选择elem.nextElementSibling.classList.remove("glyphicon-ok")// 从元素的父元素的选择器集合中添加has-error类选择器elem.parentElement.classList.add("has-error")// 向元素的下一个兄弟元素的选择器集合中添加glyphicon-remove类选择器elem.nextElementSibling.classList.add("glyphicon-remove")}}// 传入form表单input标签的name属性和value属性验证输入是否合法static verify(name, value) {switch (name) {case "user":return /^\w{8,16}$/.test(value);case "password":return /^(?=\D+\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9_$#@!~]{8,16}$/.test(value);case "name":return /^[\u4e00-\u9fd5]{2,4}$/.test(value);case "age":return /^\d$|^[1-9]\d$|^1[0-2]\d$/.test(value);case "tel":return /^1[3-9]\d{9}$/.test(value);case "email":return /^\w+\@\w+\.\w+(\.\w+)?$/.test(value);default:return true;}}
}

8.编写注册页面的模板 register.js

注意!!!

自学一下bootstrap前端框架

网址 :全局 CSS 样式 · Bootstrap v3 中文文档 | Bootstrap 中文网 (bootcss.com)

// 注册模板
// 引入ajax的类
import AJAX from "../js/ajax.js";
// 引入验证表单的类
import VerifyForm from "../js/VerifyForm.js";
const registerHTML = `<h3 class="text-center">注册用户</h3><div class="row"><form action="" class="col-xs-8 col-xs-offset-2"><!-- <div class="form-group has-success has-feedback"><label class="control-label" for="user">用户名</label><input type="text" class="form-control" id="user" /><span class="glyphicon glyphicon-ok form-control-feedback"></span></div> --><div class="form-group has-feedback"><label class="control-label" for="user">用户名:</label><input type="text" class="form-control" id="user" name="user" /><span class="glyphicon form-control-feedback"></span></div><div class="form-group has-feedback"><label class="control-label" for="password">密码:</label><inputtype="password"class="form-control"id="password"name="password"autocomplete/><span class="glyphicon form-control-feedback"></span></div><div class="form-group has-feedback"><label class="control-label" for="name">姓名:</label><input type="text" class="form-control" id="name" name="name" /><span class="glyphicon form-control-feedback"></span></div><div class="form-group has-feedback"><label class="control-label" for="name">性别:</label><label class="radio-inline"><input type="radio" name="sex" id="gentleman" value="男" checked/> 男士</label><label class="radio-inline"><input type="radio" name="sex" id="lady" value="女" /> 女士</label></div><div class="form-group has-feedback"><label class="control-label" for="age">年龄:</label><input type="text" class="form-control" id="age" name="age" /><span class="glyphicon form-control-feedback"></span></div><div class="form-group has-feedback"><label class="control-label" for="tel">电话:</label><input type="text" class="form-control" id="tel" name="tel" /><span class="glyphicon form-control-feedback"></span></div><div class="form-group has-feedback"><label class="control-label" for="email">邮箱:</label><input type="text" class="form-control" id="email" name="email" /><span class="glyphicon form-control-feedback"></span></div><div ><button type="submit" class="btn btn-primary col-xs-offset-4">注册</button><button type="button" class="btn btn-success col-xs-offset-1 loginbn">登录</button></div></form></div>`
export default function (content) {// 当点击注册按钮时,将注册模板注入到注册页面中content.innerHTML = registerHTML;// 获取表单var form = content.querySelector("form");// 侦听登录的点击事件,调用jumpLogin函数form.querySelector(".loginbn").addEventListener("click", jumpLogin);// 侦听表单的提交事件form.addEventListener("submit", submitHandler);// 侦听表单中的input是否有填写form.addEventListener("input", inputHandler);
}function submitHandler(e) {// 阻止表单的默认提交行为e.preventDefault();// 获取表单提交的数据var fd = new FormData(this);// 判断表单中的input框是否输入完成var data = {};for (var [key, value] of fd) {if (!VerifyForm.verify(key, value)) {// 没有输入数据的input框会进行集焦显示提醒this.querySelector("[name=" + key + "]").focus();return;}// 每一个input验证完毕并且都填写了合法的内容再放入data对象中data[key] = value;}// 调用提交注册表单的函数registerForm(data)
}function inputHandler(e) {// 表单中不是input框和input框中的name属性=sex的不进行表单验证if (e.target.nodeName !== "INPUT" || e.target.name === "sex") return;// age的input框只能输入数字if (e.target.name === "age") {e.target.value = e.target.value.replace(/\D/g, "");}// 调用验证表单的类VerifyForm.setForm(e.target);
}// 提交表单的函数
async function registerForm(data) {// 调用ajax通信,发送请求let result = await AJAX.post("/register", data);// 弹出警示框返回表单是否提交成功的信息alert(result.data.result.msg)// 如果提交不成功,调用jumpLogin函数,重新提交表单if (!result.data.err) {jumpLogin();}
}// 侦听登录的点击事件就跳转到登录页面
function jumpLogin() {var evt = new MouseEvent("click", { bubbles: true });loginform.firstElementChild.children[1].firstElementChild.dispatchEvent(evt);}

9.编写登录页面的模板 login.js

// 登录模板
import VerifyForm from "../js/VerifyForm.js";
import AJAX from "../js/ajax.js";const loginText = `<h3 class="text-center">登录</h3><div class="row"><form action="" class="col-xs-8 col-xs-offset-2"><!-- <div class="form-group has-success has-feedback"><label class="control-label" for="user">用户名</label><input type="text" class="form-control" id="user" /><span class="glyphicon glyphicon-ok form-control-feedback"></span></div> --><div class="form-group has-feedback"><label class="control-label" for="user">用户名:</label><input type="text" class="form-control" id="user" name="user" /><span class="glyphicon form-control-feedback"></span></div><div class="form-group has-feedback"><label class="control-label" for="password">密码:</label><inputtype="password"class="form-control"id="password"name="password"autocomplete/><span class="glyphicon form-control-feedback"></span></div><div ><button type="submit" class="btn btn-primary col-xs-offset-4">登录</button><button type="button" class="btn btn-success col-xs-offset-1">注册</button></div></form></div>`
export default function (content) {// 当点击登录按钮时,将登录模板注入到登录页面中content.innerHTML = loginText;// 获取表单var form = content.querySelector("form");// 侦听表单的提交事件form.addEventListener("submit", submitHandler);// 侦听表单中的input是否有填写form.addEventListener("input", inputHandler);
}function submitHandler(e) {// 阻止表单的默认提交行为e.preventDefault();// 获取表单提交的数据var fd = new FormData(this);var data = {};// 判断表单中的input框是否输入完成for (var [key, value] of fd) {if (!VerifyForm.verify(key, value)) {// 没有输入数据的input框会进行集焦显示提醒this.querySelector("[name=" + key + "]").focus();return;}// 每一个input验证完毕并且都填写了合法的内容再放入data对象中data[key] = value;}// 调用提交登录表单的函数login(data);
}function inputHandler(e) {// 表单中不是input框不进行表单验证if (e.target.nodeName !== "INPUT") return;// 调用验证表单的类VerifyForm.setForm(e.target);
}async function login(data) {// 调用ajax通信,发送请求let result = await AJAX.post("/login", data);// 弹出警示框返回表单是否提交成功的信息alert(result.data.result.msg);// 如果提交不成功的情况if (!result.data.err) {// console.log(result.data.result);// 存储用户名localStorage.user = result.data.result.user;// 存储token令牌localStorage.token = result.data.result.token;}
}

10. 清除index.html 文件的内容,重新编写index.html 文件。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><!-- 引入文件 --><link rel="stylesheet" href="./css/bootstrap.css"><script src="./js/jquery.js"></script><script src="./js/bootstrap.js"></script>
</head><body><div class="container"><!-- 导航条 --><div class="row"><p class="navbar-text navbar-right">张三<a href="#" style="margin-left: 10px" class="navbar-link">退出登录</a></p></div><!-- 切换注册和登录页面 --><div class="col-xs-6 col-xs-offset-3 row" id="loginform"><ul class="nav nav-tabs nav-justified"><li class="active"><a href="javascript:void(0)" id="register-tab">注册</a></li><li><a href="javascript:void(0)" id="login-tab">登录</a></li></ul><div class="content"></div></div><!-- 表单 --><div id="list"></div></div><script type="module">import register from "./template/register.js";import login from "./template/login.js";// loginform:登录的表单,content:登录表单中的内容,prev:切换var loginform, content, prev;init();function init() {// 获取登录的表单loginform = document.querySelector("#loginform");// 获取登录表单中的内容content = loginform.querySelector(".content");// 侦听点击事件loginform.addEventListener("click", tabClickHandler);// 抛发事件var evt = new MouseEvent("click", { bubbles: true });loginform.querySelector("#register-tab").dispatchEvent(evt);}function tabClickHandler(e) {// 判断是否点击了a标签,这里是没有点击a标签if (e.target.nodeName != "A") return;// 点击后切换,prev有值是显示的if (prev) {// 将prev对应的页面隐藏到prev.className = "";}// 被点击元素的父元素prev = e.target.parentElement;// 给父元素添加类选择器,将另一个页面显示出来prev.className = "active";// 根据切换的页面使用对应的页面表单if (e.target.id === "register-tab") {register(content);} else {login(content);}}</script>
</body></html>

7.2 登录页面切换到注册页面、登录功能

1. 继续完善login.js 。

2. 在js文件夹下新建并编写一个Hash.js的文件,用路由方法来实现登录页面和注册页面的跳转。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com