1.?jQuery?发送?ajax?请求 :
+?jQuery?内的?ajax?封装模式就是按照?回调函数?和?promise?两种形式进行封装的
+?你使用的时候,?可以按照 回调函数 的形式使用,?也可以按照?promise?的形式使用
?1.?ajax( )
+?专门用来发送?ajax?请求的方法
+?使用不需要选择到元素
+?语法:?$.ajax({?对本次请求的配置信息?})
=>?url :?必填 ,?表示 请求地址
=>?method?:?选填,?表示 请求方式 (默认是?GET)
??~>?method?可以写成?type?也可以写成?method
=>?data :?选填,?表示携带给后端的 参数 (默认是?空字符串)
??~>?在?jquery?内,?不光可以写查询字符串格式
??~>?也可以直接书写?对象?数据类型
=>?async :?选填,?表示是否 异步 (默认是?true?,?表示异步)
=>?dataType?:?选填,?表示是否 解析 后端返回的数据,
默认是?'string'?不解析,?选填?' json '?表示解析
=>?success :?选填,?表示 成功 的回调函数
=>?error :?选填,?表示 失败 的回调函数?(?jquery?认为失败就是失败?)
??~>?失败可以不光是请求失败
??~>?如果解析失败也会走失败?error?的回调函数
=>?timeout :?选填,?默认是?true(?表示永久?),?可以选填一个数字,?表示 超时时间 ,?单位是?ms
=>?cache :?选填,?表示是否 缓存?,?在发送?ajax?请求的时候默认是?true,?表示缓存
??~>?选填为?false?的时候,?表示不缓存
??~>?额外给你添加一个参数叫做?_?,?值是?时间戳
=>?context :?选填,?表示?ajax?回调函数的 上下文?,?回调函数内的?this?指向
??~>?默认是?jquery?自己封装的?ajax?对象
??~>?可以自己调整,?填写任意内容
=>?headers :?选填,?默认是没有,?当你需要额外设置 请求头 信息的时候
??~>?可以在这个?headers?内书写
??~>?注意:?headers?的值是一个?对象数据类型,
把你要设置的请求头直接书写在对象内就可以了
// ( 1 )
$.ajax({
url: './ajax', // 必填 , 请求的地址
method: 'POST', // 选填 , 请求的方式(默认是'GET')
data: { name: 'Jack', age: 18 },// 选填, 发送请求时携带的参数
dataType: 'json', // 选填, 默认是 string ,不解析, 'json'表示解析
success: function (res) { console.log(res) } // 选填, 成功的回调函数
})
// ( 2 )按照 promise 的形式书写
$.ajax({
url: './ajax', // 必填 , 请求的地址
method: 'POST', // 选填 , 请求的方式(默认是'GET')
data: { name: 'Jack', age: 18 },// 选填, 发送请求时携带的参数
dataType: 'json' // 选填, 默认是 string ,不解析, 'json'表示解析
}).then(res => console.log(res)) // 选填, 成功的回调函数
// ( 3 )
async function fn() {
const res = await $.ajax({
url: './ajax', // 必填 , 请求的地址
method: 'POST', // 选填 , 请求的方式(默认是'GET')
data: { name: 'Jack', age: 18 },// 选填, 发送请求时携带的参数
dataType: 'json' // 选填, 默认是 string ,不解析, 'json'表示解析
})
console.log(res)
}
fn()
const obj = { name: '我是自己创建的一个 obj 对象' }
$.ajax({
url: './ajax',
method: 'GET',
data: { name: 'Jack', age: 18 },
dataType: 'json',
success: function (res) { console.log('成功', this) },
error: function (xhr, err, info) {
// xhr: jquery 封装的 ajax 对象
// err: 错误信息
// info: 错误信息的描述
console.log('请求失败了')
console.log(xhr)
console.log(err)
console.log(info)
},
// 表示超过 1000ms 服务器还没有给出响应, 那么直接取消请求, 认定请求失败
timeout: 1000,
// 会在请求发送的时候, 额外添加一个参数
// 表示不缓存, 会给你添加一个参数, 叫做时间戳
cache: false,
// 表示把 success 回调函数内的 this 指向 obj 这个对象
context: obj,
// 表示你所有需要额外设置的请求头信息
headers: {
authorization: 'abcdef',
abc: 100
}
})
1. $.get( ) - 专门发送 get 请求的方法
+ 语法: $.get(请求地址, 携带的参数, 回调函数, 是否解析) ? ? ? ? ? =>?携带的参数: 可以选填, 可以是查询字符串, 也可以是 对象 ? ? ? ? +?按照 promise 和 回调函数 两种方式封装的
// 1. 发送一个 get 请求
$.get('./ajax.php', 'a=100&b=200', res => console.log(res), 'json')
2. $.post( ) - 专门发送 post 请求的方法
+ 语法: $.post(请求地址, 携带的参数, 回调函数, 是否解析) ?? ??? ??? ?=> 携带的参数: 可以选填, 可以是查询字符串, 也可以是 对象 ? ? ? ? + 按照 promise 和 回调函数 两种方式封装的
// 2. 发送一个 post 请求
$.post('./ajax.php', { username: 'zhangsan', password: '123456' }).then(res => console.log(res))
2.?jQuery?发送?jsonp?请求 :?
回顾?+?jsonp?原理?: +?利用?script?标签能把请求回来的内容当做?js?代码执行 +?利用?src?不受同源策略的影响 +?要求: =>?后端返回的是一个可以执行的合法的?js?代码 =>?后端返回的内容是一个?'函数名(数据)'?这样的字符串 =>?前端在发送请求的时候,?把准备好的函数名给到后端
使用的方法是? $.ajax( ) + 要求: dataType 必须写成 'jsonp' ? => dataType 你写成 json 或者 string 的时候, 都是发送 ajax 请求 ? => dataType 你写成 jsonp 的时候, 就不会发送 ajax 请求了,? ? 而是 创建 script 标签 发送 jsonp 请求 + 注意: 在配置项内有两个专门为 jsonp 请求设置的配置项 ? 1. 会自动帮你添加一个参数叫做 callback, 表示我准备好的回调函数 ?? ?=> 名字是 jquery 随机组成的 ?? ?=> 名字可以修改 ?? ?=> 使用 jsonpCallback 字段 : 表示函数名 ? 2. jquery 默认添加的字段名字叫做 callback ?? ?=> 表示给后端传递回调函数名的字段 ?? ?=> 可以修改的 ?? ?=> 使用 jsonp 字段修改 ? 3. cache 缓存机制 ?? ?=> 当你发送 ajax 请求的时候, cache 默认值是 true, 表示缓存,? ?? ?不会添加一个时间戳作为参数 ?? ?=> 当你发送 jsonp 请求的时候, cache 默认值是 false, 表示不缓存,? ?? ?会添加一个时间戳作为参数
$.ajax({
url: './jsonp.php',
// 表示发送一个 jsonp 请求
dataType: 'jsonp',
// success: function (res) { console.log(res) },
jsonpCallback: 'fn', // jsonp 请求的时候回调函数的名称
jsonp: 'cb' // 表示在参数中把 回到函数的 字段名改成 cb
})
function fn(res) {
console.log('我是 fn 函数')
console.log(res)
}
// 百度搜索引擎
$.ajax({
url: 'https://www.baidu.com/sugrec',
data: {
pre: 1,
p: 3,
ie: 'utf-8',
json: 1,
prod: 'pc',
from: 'pc_web',
sugsid: '34099,33970,34004,33855,33607,26350,22159',
wd: 'a',
req: 2,
csor: 1
},
// 表示发送一个 jsonp 请求
dataType: 'jsonp',
// 表示我准备好的函数叫做 fn 函数
jsonpCallback: 'fn',
// 表示在参数中把 回到函数的 字段名改成 cb
jsonp: 'cb',
cache: true,
success (res) {
console.log(res)
}
})
3. jQuery?内的全局?ajax?生命周期函数 :
+?也叫作?ajax?的?钩子函数
1.?ajaxStart(?)?-?请求开始
??+?语法:?$(window).ajaxStart(function?()?{})
??+?时机:?同一个作用域下的第一个?ajax?发送的时候,?会触发执行
2.?ajaxSend(?)?-?发送之前
??+?语法:?$(window).ajaxSend(function?()?{})
??+?时机:?会在每一个请求发送出去之前?触发执行
3.?ajaxSuccess(?)?-?成功之后
??+?语法:?$(window).ajaxSuccess(function?()?{})
??+?时机:?会在每一个请求成功了之后?触发执行
4.?ajaxError(?)?-?失败之后
??+?语法:?$(window).ajaxError(function?()?{})
??+?时机:?会在每一个请求失败了之后?触发执行
5.?ajaxComplete(?)?-?完成之后
??+?语法:?$(window).ajaxComplete(function?()?{})
??+?时机:?会在每一个请求完成之后?触发执行,?不管成功还是失败,?都是完成
6.?ajaxStop(?)?-?请求结束
??+?语法:?$(window).ajaxStop(function?()?{})
??+?时机:?同一个作用域下的最后一个?ajax?完成以后,?触发执行
// 1. ajaxStart() - 请求开始
$(window).ajaxStart(function () { console.log('第一个请求发送之前, ajax 开始') })
// 2. ajaxSend() - 发送之前
$(window).ajaxSend(function () { console.log('有一个请求发送出去了') })
// 3. ajaxSuccess() - 成功之后
$(window).ajaxSuccess(function () { console.log('有一个请求成功了^_^') })
// 4. ajaxError() - 失败之后
$(window).ajaxError(function () { console.log('有一个请求失败了') })
// 5. ajaxComplete() - 完成之后
$(window).ajaxComplete(function () { console.log('有一个请求完成') })
// 6. ajaxStop() - 请求结束
$(window).ajaxStop(function () { console.log('最后一个请求完成了') })
?案例 :?利用钩子函数完成一个 loading 效果
button {
padding: 20px;
font-size: 20px;
}
div {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
background-color: rgba(255, 255, 255, .5);
display: flex;
justify-content: center;
align-items: center;
display: none;
}
<button>发送请求</button>
<div class="loading">
<img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fhbimg.b0.upaiyun.com%2F16f7121aedf9990f3ddd8725e99fe4d8369e06692d18-J0TUcl_fw658&refer=http%3A%2F%2Fhbimg.b0.upaiyun.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630134491&t=e1a2d516e36c3b9be945e4faebf565da" alt="">
</div>
<script src="./jquery/jquery.min.js"></script>
// 1. 什么时候开始显示 loading 效果
// 只要有一个请求发送出去, 就要显示
$(window).ajaxSend(() => $('.loading').css('display', 'flex'))
// 2. 什么时候小时 loading 效果
// 只要有一个请求完成了, 就要消失
$(window).ajaxComplete(() => $('.loading').hide())
// 3. 点击按钮发送请求
//(可自己配置一个 ajax.php 文件, 需要在本地打开)
$('button').click(() => {
$.get('./ajax.php')
})
可将网络切换到弱的 3G 状态下, 查看效果更佳 :?
4.?jQuery?的入口函数 :
+ 语法: $(window).ready(function () { ... }) + 注意: 会在页面 DOM 结构加载完毕后执行 + 类似于: window.onload = function () {} + 区别: ? => window.onload 是所有 资源 加载完毕后触发 ? => jQuery 入口函数是只要 html 结构加载完毕就触发了 + 简写: ? => jQuery 的入口函数有一个简写形式 ? => $(function () { ... })
<img src="https://img2.baidu.com/it/u=3228549874,2173006364&fm=26&fmt=auto&gp=0.jpg" alt="">
<script src="./jquery/jquery.js"></script>
// 1. 入口函数
// 1-1. onload
window.onload = function () { console.log('页面所有资源加载完毕') }
// 1-2. 入口函数
$(window).ready(function () {
console.log('jQuery 的入口函数')
console.log('DOM 结构加载完毕了')
})
// 入口函数简写 :
$(function () {
console.log('入口函数')
console.log('DOM 结构加载完毕了')
})
5.?jQuery?的多库并存 :
+?如果你引入了别的框架插件等第三方文件内容也是使用? $? 和? jQuery? 这个名字
+?那么你把?jQuery?引入在最后面
+?通过?jQuery?的?语法来还原?$?和?jQuery
+?jQuery?可以交出?$?和?jQuery?的控制权给别人
?1.?还原?$
+?语法:?$.noConflict( )
??+?这个代码一旦执行,就会让出?$?这个变量的控制权
??+?jQuery?不再占用?$?这个名字了
? $.noConflict( )??
2.?还原?$?和?jQuery
+?语法:?$.noConflict(true)
??+?这个代码一旦执行,?就会让出?$?和?jQuery?的控制权
??+?jQuery?不再占用?$?和?jQuery?这两个名字了
??$.noConflict(true)??
3.?直接定义行的控制权
??+?直接接受?$.noConflict( )?的 返回值 ,?就是新的控制权
??+?你自己定义一个新的名字当做?jQuery?的名字
??const love?=?$.noConflict(true)??
6.?jQuery?实现深浅拷贝 :
1. 深浅拷贝
+?在复制一个数据类型的时候(特指复杂数据类型,?数组或者对象)
+?在?JS?内,?对于?"复制"?有三个级别 :
??1.?赋值
??2.?浅拷贝
??3.?深拷贝
1.?赋值 :
??+?简单的地址复制
??+?使用?赋值符号( = )?进行的操作
??+?对于基本数据类型,?赋值之后两个变量之间没有任何关系
??+?对于复杂数据类型,?赋值之后两个变量操作同一个数据存储空间
// 1. 赋值
let n1 = 5
// 把 n1 的值赋值给了 n2
let n2 = n1
console.log(n1, n2) // 5 5
n2 = 10
console.log(n1, n2) // 5 10
const o1 = { name: 'Jack' }
// 进行赋值操作, 把 o1 的值赋值给了 o2
// 因为 o1 这个变量内存储的是指向一个 对象数据类型 的空间地址
// 赋值的过程中, 就是把 o1 存储的地址赋值给了 o2
// 所以给到 o2 的依旧是一个 地址
// 从此以后 o1 和 o2 操作一个对象存储空间
const o2 = o1
console.log(o1, o2)
// 使用任意一个变量名修改对象空间内的成员
o2.name = 'Rose'
console.log(o1, o2)
?
?
2.?浅拷贝 :
=>?创建一个和原先数据结构一模一样的数据结构
+ 假如原先是个数组数据类型,?那么就新创建一个数组
+?假如原先是个对象数据类型,?那么就新创建一个对象
=>?通过?for?in?循环去遍历原先数据结构
+?把里面的每一个数据分别在新的数据结构中复制一份
+?对于一维数据结构有效
+?如果是多维数据结构,没有意义?,?那么从第二维度开始,?依旧是操作同一个存储空间
// 2. 浅拷贝
const o1 = { name: 'Jack', age: 18, info: { height: 180 } }
// 2-1. 创建一个和原先数据结构一模一样的结构
const o2 = {}
// 2-2. 循环遍历原始数据结构
for (const key in o1) {
// 2-3. 分别在新的数据结构中进行赋值
// 在进行 for in 遍历的时候
// 在这里, 当 key === info 的时候
// o1[key] 存储的也是一个地址
// o2[key] 就是把 o1[key] 存储的地址复制了一份过去
// 从此以后, o1 和 o2 虽然是两个数据空间
// 但是 o1.info 和 o2.info 操作的是一个数据空间
// o2.info = o1.info
// 因为 info 内存储的是一个 地址
// 赋值以后, o2.info 和 o1.info 存储的是同一个地址
o2[key] = o1[key]
}
// 此时 o1 和 o2 不是一个对象存储空间
// 只是长得一模一样的两个对象存储空间
// 用任意一个区操作的时候, 另外一个不会改变
console.log(o1, o2)
// 修改
o2.name = 'Rose'
o2.age = 20
console.log(o1, o2)
// 修改第二维度 info 内的数据
o2.info.height = 200
console.log(o1, o2)
知识点扩展 :
// 准确的判断所有数据类型
// 语法: Object.prototype.toString.call(你要判断的数据类型)
// 返回值: 该数据类型的 类型字符串 '[object 类型]'
console.log(Object.prototype.toString.call({})) // Object
console.log(Object.prototype.toString.call([])) // Array
console.log(Object.prototype.toString.call(123)) // Number
console.log(Object.prototype.toString.call('123')) // String
console.log(Object.prototype.toString.call(true)) // Boolean
console.log(Object.prototype.toString.call(null)) // Null
console.log(Object.prototype.toString.call(undefined))// Undefined
console.log(Object.prototype.toString.call(/^$/)) // RegExp
console.log(Object.prototype.toString.call(new Date()))// Date
console.log(Object.prototype.toString.call(function () {}))//Function
?
// 如果一个数据是数组数据类型 // 那么当你访问他的 constructor 的时候, 自己没有, 就要去自己的 __proto__ 上查找 // 数组的 __proto__ 就是 Array.prototype // Array.prototype 上面的 constructor 就是 Array
// 如果一个数据是对象数据类型 // 那么当你访问他的 constructor 的时候, 自己没有, 就要去自己的 __proto__ 上查找 // 对象的 __proto__ 就是 Object.prototype // Object.prototype 上面的 constructor 就是 Object
3.?深拷贝 :
=>?不停地重复浅拷贝的工作
=>?复制出一份完全一模一样的数据结构
=>?不管多少维度的数据结构,?都能完整独立的复制过来
=>?实现方式:
+?使用?递归?的方式进行逐层数据结构的?遍历数据并赋值
+?当我循环遍历的时候,?如果碰到的还是复杂数据类型
+?那么就递归进行遍历
// 3. 深拷贝
const o1 = {
name: 'Jack',
age: 18,
info: {
weight: 180,
height: 180,
desc: {
msg: '这个人很懒, 什么都没有留下!'
}
},
hobby: ['吃饭', '睡觉', ['篮球', '足球']]
}
const o2 = {}
// 3-1. 书写函数来完成(递归函数)
// 使用递归的方式进行深拷贝
function deepCopy(o2, o1) {
// 做: 把 o1 内的所有数据全部拷贝到 o2 内部
// console.log(o1, o2)
//3-2. 直接循环遍历 o1 数据
for (let key in o1) {
// console.log(key);
// 判断, 如果是 对象数据类型 或者 数组数据类型, 不进行赋值
// 否则, 才进行赋值
// 如果 o1[key] 是一个对象数据类型
// o2[key] 也要创建为一个对象数据类型
// 如果 o1[key] 是一个数组数据类型
// o2[key] 也要创建为一个数组数据类型
// 如果 o1[key] 是一个基本数据类型
// o2[key] 直接赋值
if (Object.prototype.toString.call(o1[key]) === '[object Object]') {
// 是对象
// console.log('o1[key] 是一个对象数据类型 : ', key)
o2[key] = {}
// 在这个位置, o1[key] 是一个对象数据类型
// o2[key] 也是一个数据类型
// o1[key] 里面的每一个数据复制一份到 o2[key]
deepCopy(o2[key], o1[key])
} else if (o1[key].constructor === Array) {
// 是数组
// console.log('o1[key] 是一个数组数据类型 : ', key)
o2[key] = []
// 把 o1[key] 内部的所有数据放在 o2[key] 内
deepCopy(o2[key], o1[key])
} else {
// console.log('o1[key] 是一个基本数据类型 : ', key)
// 直接复制
o2[key] = o1[key]
}
}
}
// 将来使用的时候
deepCopy(o2, o1)
console.log(o1, o2)
// 修改数据
o2.info.desc.msg = 'hello world'
4.?深拷贝?-?方案2
??+?只能是在?对象?和?数组?数据结构中使用
??+?不能有函数
??+?利用?json?格式字符串
??4-1.?把源数据转换成 json?格式字符串
??4-2.?把?json?格式字符串转换回?js?数据类型
// 4. 深拷贝 - 方案2
const o1 = { name: 'Jack', age: 18, info: { weight: 180, height: 180, desc: { msg: '你好 世界' } }, hobby: [ '吃饭', '睡觉' ] }
console.log(o1)
// 把 o1 转换成 json 格式字符串
// 现在的 jsonStr 就是基本数据类型
const jsonStr = JSON.stringify(o1)
console.log(jsonStr)
// 把 s 转换成一个 JS 的对象格式
const o2 = JSON.parse(jsonStr)
console.log(o2)
// 修改
o2.info.desc.msg = 'hello world'
console.log(o1, o2)
jQuery 内有实现深浅拷贝的方法 : + $.extend( )
const o1 = {
name: 'Jack',
age: 18,
info: {
weight: 180,
height: 180,
desc: {
msg: '这个人很懒, 什么都没有留下!',
title: '你好 世界'
}
},
hobby: [ '吃饭', '睡觉', [ '篮球', '羽毛球', '足球' ] ]
}
+ 浅拷贝 : ? => 语法: $.extend(对象1, 对象2, 对象3, ...) ? => 作用: 把从 对象2 开始的所有对象内的数据进行浅拷贝到 对象1 内 ? => 实现的是浅拷贝
// 1. 实现浅拷贝
// 把 o1 内的所有数据进行浅拷贝到 o2 身上
let o2 = {}
$.extend(o2, o1)
console.log(o1, o2)
// 修改一下数据
o2.name = 'Rose'
// 第二维度修改
o2.info.height = 200
console.log(o1, o2)
+ 深拷贝: ? => 语法: $.extend(true, 对象1, 对象2, 对象3, ...) ? => 作用: 把从 对象2 开始的所有对象内的数据进行深拷贝到 对象1 内 ? => 实现的是深拷贝
// 2. 实现深拷贝
let o2 = {}
$.extend(true, o2, o1)
// console.log(o1, o2)
// 修改
o2.name = 'Tom'
o2.info.height = 250
o2.info.desc.msg = '这个人更懒'
console.log(o1, o2)
总结一下 :?$(?)?
??1.?$('选择器')?=>?获取页面元素
??2.?$(DOM节点)?=>?把?DOM?节点转换成?jquery?的元素集合
??3.?$('html?结构字符串')?=>?创建节点
??4.?$(函数)
????=>?jQuery?的入口函数,?会在?DOM?结构加载完毕后执行
|