本课目标
- 熟练掌握代码的封装
- 理解跨域的基本实现原理
- 理解XML格式数据结构
1. 写程序为什么需要封装
-
函数封装是一种函数的功能,它把一个程序员写的一个或者多个功能通过函数、类的方式封装起来,对外只提供一个简单的函数接口。 当程序员在写程序的过程中需要执行同样的操作时,程序员(调用者)不需要写同样的函数来调用,直接可以从函数库里面调用。
-
目的:化繁为简,不写重复的代码。
-
课堂案例:ajax调用过程函数封装.html
-
课堂案例:01.ajax调用封装测试.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/ajax2.js"></script>
</head>
<body>
<script>
/*
测试Ajax方法 GET方法的测试
*/
/*
ajax({
type:'GET',
url:'http://www.有效地址,
success: function(data,request){
console.log("请求成功")
console.log(data)
},
error: function(data,request){
console.log("请求失败")
console.log(data)
console.log(request)
}
}) ; */
/*
测试Ajax方法 POST方法的测试
*/
/* ajax({
type:'POST',
url:'http://www.有效地址,
data:{
args:'哈哈',
password:'12345'
},
success: function(data,request){
console.log("post请求成功")
console.log(data)
},
error: function(data,request){
console.log("post请求失败")
console.log(data)
console.log(request)
}
}) ; */
/*
测试请求参数为JSON格式
*/
ajax({
type:'POST',
url:'http://www.有效地址,
data:{
username:"zhangsan",
password:"ddd",
gender:1,
},
headr:{
'Content-Type':"application/json"
},
success: function(data,request){
console.log("json request format 请求成功")
console.log(data)
},
error: function(data,request){
console.log("json request format 请求失败")
console.log(data)
console.log(request)
}
}) ;
</script>
</body>
</html>
2. 数据渲染模板的使用
-
课堂案例:02.template模板引擎基本用法.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/template-web.js"></script>
</head>
<body>
<!--
需求:将服务端返回的数据,梵高页面html标签中
思路:基于document生成新的标签,再将标签插入到指定的元素当中
使用框架实现: template-web的使用方式
{{}}:取值的
-->
<ul id="ul1">
<script type="text/html" id="tpl1">
<li>{{username}}</li>
</script>
</ul>
<!--
通过Ajax到后台加载数据...
-->
<script>
/*
将数据跟模板进行结合
第一个参数:是模板的id
第二个参数:是json格式的数据
*/
const tmpContent1 = template('tpl1',{"username":"比屋教育"});
//渲染之后的数据
console.log(tmpContent1)
//插入结果到指定的地方
document.querySelector("#ul1").innerHTML = tmpContent1;
</script>
</body>
</html>
3. 关联搜索案例开发
-
input事件:元素的
value
被修改时,会触发input
事件 -
课堂案例:03.关联搜索案例开发.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<script src="js/template-web.js"></script>
<script src="js/ajax2.js"></script>
<style type="text/css">
.container{
padding-top: 100px;
}
.list-group{
display:none;
}
</style>
</head>
<body>
<div class="container">
<div class="form-group">
<input type="text" class="form-control" placeholder="请输入关键字" id="search1">
<ul class="list-group" id="list-box">
<!-- <li>java</li>
<li>前端</li> -->
<script type="text/html" id="tpl1">
{{each haha}} <!--遍历 -->
<li class="list-group-item">{{$value}}</li> <!-- $value获取lis里面的每一个值 -->
{{/each}}
</script>
</ul>
</div>
</div>
<script>
/*
实现通过关键字搜索的请求
*/
const search1Obj = document.querySelector("#search1")
const ul1Obj = document.querySelector("#list-box")
//当一个 <input>, <select>, 或 <textarea> 元素的 value 被修改时,会触发 input 事件。
search1Obj.oninput = function(){
console.log(this.value)
//输入的关键字
const key = this.value;
//非空判断
if(key.trim().length==0){
ul1Obj.style.display = 'none';
//结束程序
return ;
}
//如果不为空就发送请求
ajax({
type:"GET",
url:'http://www.有效地址,
data:{
keyword:key
},
success:function(data){
//判断服务端是否有数据返回
if(data.length!=0){
//创建li标签,放入到ul标签中
//使用模板来渲染数据
/*
data:是一个字符串
问题:需要创建多个li标签,然后把打他的值放进去,但是打他是一个字符串
*/
const dataArr = data.split(",") //返回的值是 , 分割的
const liss = template("tpl1",{haha:dataArr});
// console.log(lis);
ul1Obj.innerHTML = liss;
ul1Obj.style.display = 'block'
}
}
})
}
</script>
</body>
</html>
4. 省市区三级联动案例开发
-
课堂案例:04.省市区联动.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<script src="js/template-web.js"></script>
<script src="js/ajax2.js"></script>
<style>
.container {
padding-top: 100px;
}
</style>
</head>
<body>
<div class="container">
<!-- 显示在一行 -->
<div class="form-inline">
<!-- 省 -->
<div class="form-group"> <!-- form-group对div优化 -->
<select class="form-control" id="provinces"></select> <!-- form-control对select框优化 -->
</div>
<!-- 市 -->
<div class="form-group">
<select class="form-control" id="citys">
<option value="">请选择城市</option>
</select>
</div>
<!-- 区县 -->
<div class="form-group">
<select class="form-control" id="areas">
<option value="">请选择区县</option>
</select>
</div>
</div>
</div>
<!--
省份的模板
provinces = [
{
"id":"100",
"name":"河北省"
},
{
"id":"101",
"name":"河南省"
},
{
"id":"102",
"name":"山东省""
},
]
-->
<script type="text/html" id="tpl1">
<option>请选择省份</option>
{{each provinces}}
<option value="{{$value.id}}">{{$value.name}}</option>
{{/each}}
</script>
<!-- 城市的模板 -->
<script type="text/html" id="tpl2">
<option>请选择城市</option>
{{each citys}}
<option value="{{$value.id}}">{{$value.name}}</option>
{{/each}}
</script>
<!-- 区县的模板 -->
<script type="text/html" id="tpl3">
<option>请选择区县</option>
{{each areas}}
<option value="{{$value.id}}">{{$value.name}}</option>
{{/each}}
</script>
<script>
//从服务端获取数据
const provinceObj = document.querySelector("#provinces")
const cityObj = document.querySelector("#citys")
const areaObj = document.querySelector("#areas")
//发送ajax
ajax({
type: "GET",
url: "http://www.有效地址",
//返回的数据
// [{"name":"黑龙江省","id":"001"},{"name":"四川省","id":"002"},{"name":"湖北省","id":"003"},{"name":"江苏省","id":"004"}]
success: function (data) {
if (data.length != 0) {
//渲染数据
console.log(data)
console.log(JSON.parse(data))
/*
data参数: 模板需要的是对象,但是后端返回的是字符串,所以没法显示
解决办法:通过JSON.parse()转换为json数组格式对象
*/
const options = template("tpl1", {provinces: JSON.parse(data)})
// console.log(options)
provinceObj.innerHTML = options;
}
}
})
/*
给省份和城市绑定change事件
*/
provinceObj.onchange = function () {
const cid = this.value;
console.log(cid)
//通过pid加载城市
ajax({
type: "GET",
url: "http://www.有效地址,
data: {
id: cid
},
success:function(data){
if(data.length>0){
//渲染模板
const options = template("tpl2", {citys: JSON.parse(data)})
// console.log(options)
cityObj.innerHTML = options;
}
}
})
}
cityObj.onchange = function () {
const pid = this.value;
console.log(pid)
//通过pid加载城市
ajax({
type: "GET",
url: "http://www.有效地址,
data: {
id: pid
},
success:function(data){
if(data.length>0){
//渲染模板
const options = template("tpl3", {areas: JSON.parse(data)})
// console.log(options)
areaObj.innerHTML = options;
}else{
//当没有返回数据的时候,需要清空模板
const options = template('tpl3',{areas: null});
areaObj.innerHTML = options;
// areaObj.innerHTML = '';
}
}
})
}
</script>
</body>
</html>
5. 什么是跨域访问
- 什么是跨域: 当一个请求url的协议 、 域名 、 端口三者之间的任意一个与当前页面url不同即为跨域。
当前页面url(所在服务器) | 被请求页面url(所在服务器) | 是否跨域 | 原因 |
---|---|---|---|
http://120.78.190.136:8088/a.html | http://120.78.190.136:8088/test | 否 | 同源(协议、域名、端口号相同) |
http://www.testlocation.com/a.html | https://www.testlocation.com/test | 跨域 | 协议不同(http/https) |
http://120.78.190.136:8088/a.html | http://121.78.190.136:8088/test | 跨域 | 域名(IP)不同(testlocation/baidu) |
http://120.78.190.136:8088/a.html | http://blog.testlocation.com/test | 跨域 | 子域名不同(www/blog) |
http://120.78.190.136:8088/a.html | http://120.78.190.136:8099/test | 跨域 | 端口号不同(8080/8088) |
-
出于浏览器的
同源策略
限制:同源策略(Same Orgin Policy)是一种约定,它是浏览器核心也最基本的安全功能,它会阻止一个域的js脚本和另外一个域的内容进行交互,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源(即在同一个域)就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)。 -
课堂案例:05.非同源Ajax请求.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/ajax2.js"></script>
</head>
<body>
<script>
/*
服务端的URL: http://www.有效地址
通过Ajax访问出现错误:该资源不允许Ajax访问
*/
ajax({
type:"GET",
url:"http://www.有效地址,
success:function(data){
conosle.log(data)
}
})
</script>
</body>
</html>
6. 如何解决跨越问题
6.1 基于JSONP模式解决跨域
-
JSONP(JSON with Padding)是资源格式JSON 的一种"使用模式",可以让网页从别的服务器访问数据
-
课堂案例:06.使用jsonp向非同源服务器端请求数据1.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
/*
http://www.有效地址
该服务端程序的返回值:返回的是一个函数调用+函数参数
func(
{name: "比屋教育"}
)
*/
function func(data){
console.log("该函数被调用了,data是从服务端获取的数据 "+data);
console.log(data)//{name: "比屋教育"}
}
</script>
<!--
JSONP模式
将获取服务端资源的地址写在 script 标签的src属性中
-->
<script src="http://www.有效地址">
</script>
</body>
</html>
-
课堂案例:07.使用jsonp向非同源服务器端请求数据2.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
/*
https://www.有效地址 结果: func2({name: "比屋教育2"})
https://www.有效地址?funcname=func3 结果: func3({name: "比屋教育3"})
该服务端程序的返回值会根据参数的不同进行返回
*/
function func2(data){
console.log("func2该函数被调用了,data是从服务端获取的数据 "+data);
console.log(data)//
}
function func3(data){
console.log("func3该函数被调用了,data是从服务端获取的数据 "+data);
console.log(data)//
}
</script>
<!--
JSONP模式
将获取服务端资源的地址写在 script 标签的src属性中
总结:func3({name: "比屋教育3"})
就是利用前面定义好的函数结合服务端返回的JSONP的格式,执行前面的函数
实际上服务端返回的就是一个函数的调用
将scripy标签替换为:func3({name: "比屋教育3"})
-->
<script src="http://www.有效地址">
</script>
</body>
</html>
-
课堂案例:08.使用jsonp向非同源服务器端请求数据3.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button>基于JSONP获取服务端数据</button>
<script>
function func1(data){
console.log("该函数被调用了,data是从服务端获取的数据 "+data);
console.log(data)//
}
</script>
<script>
const btnObj = document.querySelector("button")
btnObj.onclick = function(){
//创建script标签
const scriptObj = document.createElement("script")
// http://www.biwuit.cn/spboot/test5?callback=aaa
//函数名称可以自定义,服务端会返回自定义的名称
scriptObj.src = 'http://www.biwuit.cn/spboot/test5?callback=func1'
//将script标签放入body中
document.body.appendChild(scriptObj)
//执行完后删除
// scriptObj.parentNode.removeChild(scriptObj)
//方式二:可以利用load事件 window.onload 页面加载完后执行
// scriptObj.onload 等到也买你的script标签加载完后执行
scriptObj.onload = function(){
scriptObj.parentNode.removeChild(scriptObj)
}
}
</script>
</body>
</html>
-
课堂案例:09.封装jsonp方法.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/ajax2.js"></script>
</head>
<body>
<button>测试1</button>
<!-- 每次都需要这样定义吗? -->
<!-- <script>
function func10(data){
console.log("该函数被调用了,data是从服务端获取的数据 "+data);
console.log(data)//{name: "比屋教育"}
}
</script> -->
<script>
const btnArr = document.querySelector("button")
/*
url:http://www.biwuit.cn/spboot/test5?callback=func10
返回值:func10({name: "比屋教育05"})
*/
btnArr.onclick = function () {
jsonp({
funcname: 'func10',
url: 'http://www.biwuit.cn/spboot/test5',
data: {
name: 'lisi',
age: 22
},
success: function (data) {
console.log("执行成功")
console.log(data)
}
})
}
/*
封装jsonp的加载过程
options{
funcname:''
url:''
data:{
name: 'lisi',
age:22
},
调用成功的执行函数
success:function(data){
}
}
*/
// function jsonp(options) {
// //创建一个script标签
// const scriptObj = document.createElement("script")
// let params = ''
// for (const key in options.data) {
// params += '&'+ key + '=' + options.data[key]
// }
// //生成函数的名称
// //调用服务端url
// scriptObj.src = options.url + "?callback=" + options.funcname + params;
// //将options.funcname变成全局的
// window[options.funcname] = options.success;
// // console.dir(window)
// //执行加删除
// document.body.appendChild(scriptObj)
// scriptObj.parentNode.removeChild(scriptObj)
// /*
// func10({name: "比屋教育05"}) Uncaught ReferenceError: func10 is not defined
// 解决思路: func10 一定要在全局存在,可以执行的
// */
// }
</script>
</body>
</html>
-
课堂案例:10.调用腾讯天气信息接口.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>使用JSONP的模式去获取腾讯天气接口</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<script src="js/template-web.js"></script>
<script src="js/ajax.js"></script>
<style type="text/css">
.container {
padding-top: 60px;
}
</style>
</head>
<body>
<div class="container">
<table class="table table-striped table-hover" align="center" id="box"></table>
</div>
<script type="text/html" id="tpl1">
<tr>
<th>时间</th>
<th>温度</th>
<th>天气</th>
<th>风向</th>
</tr>
{{each infos}}
<tr>
<td>{{dateFormat($value.update_time)}}</td>
<td>{{$value.degree}}</td>
<td>{{$value.weather}}</td>
<td>{{$value.wind_direction}}</td>
</tr>
{{/each}}
</script>
<script>
/*
指定自己想要的时间格式
*/
function dateFormat(date) {
const year = date.substr(0, 4);
const month = date.substr(4, 2);
const day = date.substr(6, 2);
const hour = date.substr(8, 2);
const minute = date.substr(10, 2);
const seconds = date.substr(12, 2);
return year + '年' + month + '月' + day + '日' + hour + '时' + minute + '分' + seconds + '秒';
}
//在模板中引入外部函数
/*
将返回的数据 update_time(20231208190000) 都经过dateFormat函数进行处理
将dateFormat函数导入模板中
*/
template.defaults.imports.dateFormat = dateFormat
//获取数据
/*
https://wis.qq.com/weather/common?source=pc&weather_type=forecast_1h&province=湖北省city=武汉市
*/
const tableObj = document.querySelector("#box")
jsonp({
funcname:"func11",
url:'https://wis.qq.com/weather/common',
data:{
source:'pc',
weather_type:'forecast_1h|forecast_24h',
province:'黑龙江省',
city:'哈尔滨市',
},
success:function(data){
console.log(data.data.forecast_1h)
if(data.status==200){
//渲染数据
const trs = template('tpl1',{infos:data.data.forecast_1h})
console.log(trs)
tableObj.innerHTML = trs;
}
}
})
</script>
</body>
</html>
6.2 基于CORS解决跨域
- 跨源资源共享 (CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它源(域、协议和端口),使得浏览器允许这些 origin 访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
#以下是浏览器发送给服务器的请求报文:
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
#让我们来看看服务器如何响应:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
服务端返回的 Access-Control-Allow-Origin 标头的 Access-Control-Allow-Origin: * 值表明,该资源可以被任意外源访问。
文档说明:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
Access-Control-Allow-Origin": "*",
Access-Control-Allow-Methods: 'POST',
Access-Control-Allow-Headers: 'x-requested-with, accept, origin, content-type',
Access-Control-Max-Age:10000,
Access-Control-Allow-Credentials:true
-
课堂案例:11.CORS跨域资源共享.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/ajax2.js"></script>
</head>
<body>
<button>发送请求</button>
<script>
const btnObj = document.querySelector("button")
/*
服务端没有解决跨域访问
就是没有打开如下的头部信息
Access-Control-Allow-Origin": "*"
*/
btnObj.onclick = function () {
ajax({
url: 'http://www.biwuit.cn/spboot/cross2',
success: function (data) {
console.log("访问成功")
console.log(data)
}
})
}
</script>
</body>
</html>
-
课堂案例:12.CORS服务器端解决方案.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/ajax2.js"></script>
</head>
<body>
<button>发送请求</button>
<script>
const btnObj = document.querySelector("button")
/*
服务端开放了跨域访问,设置了如下头部信息
Access-Control-Allow-Origin": "*"
*/
btnObj.onclick = function () {
ajax({
url: 'http://www.biwuit.cn/spboot/cross',
success: function (data) {
console.log("访问成功")
console.log(data)
}
})
}
</script>
</body>
</html>
7.XML数据格式的理解(了解)
-
XML:可扩展标记语言 (英語:Ex tensible M arkup L anguage,简称:XML )是一种标记语言
-
和HTML是一样的,只不过HTML中所有的标签是预定义的,只需要去使用就可以了,但是XML没有预定义标签。就是所有的标签都需要自定义。
-
XML格式与JSON格式的区别:
-
作用:都可以用来传递数据和作为配置文件
-
JSON格式比XML格式更加简洁。
-
-
-
课堂案例:13.xml格式数据解析.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="js/ajax2.js"></script>
</head>
<body>
<button>获取XML数据的格式</button>
<script>
const btnObj = document.querySelector("button")
btnObj.onclick = function () {
ajax({
url: 'http://www.biwuit.cn/spboot/xmlFormat',
success: function (data,xmlHttpRequest) {
/*
<students>
<student>
<sid>001</sid>
<name>张三</name>
</student>
<student>
<sid>002</sid>
<name>王二丫</name>
</student>
</students>
*/
//xml格式的数据
//data返回的是字符串,不方便解析
console.log(data)
//返回的是文档对象
console.log(xmlHttpRequest.responseXML)
const xmlObj = xmlHttpRequest.responseXML;
const stu1 = xmlObj.querySelector("student")
//文本才有node,现在是元素
console.log(stu1.querySelector("name").nodeValue) //null
console.log(stu1.querySelector("name").innerHTML)
/*
总结:操作xml标签,就跟操作html标签是一样的
*/
}
})
}
</script>
</body>
</html>