某度的模糊搜索
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>某度模糊搜索</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul,
li {
list-style: none;
}
#box {
width: 400px;
margin: 0 auto;
}
#ipt {
width: 400px;
}
.list {
padding: 0 30px;
width: 400px;
border: 1px solid #ccc;
display: none;
}
.list li {
height: 20px;
margin-bottom: 5px;
}
</style>
</head>
<body>
<div id="box">
<input type="text" id="ipt">
<ul class="list">
</ul>
</div>
<script src="./utils.js"></script>
<script>
function $(className) {
return document.querySelector(className)
}
var t = null
$("#ipt").oninput = function () {
// 获取输入框的内容
var ipt_value = ipt.value
// 如果内容为空,则不用发请求
if (ipt_value === "") {
$(".list").style.display = "none"
return false
}
// 判断上一次开启定时器后,t的值变化
if (t !== null) {
return false
}
t = setTimeout(function () {
// ajax 发送 http 请求
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: "hello world",
wd: ipt_value,
req: 2,
csor: 5,
// 某度自己的名字
// cb: "callback",
// 我自己定义的名字
cb: "fqniu",
_: Date.now(),
// 修改jsonpcallback的名字 注意调用ajax时 要把jsonpcallback:"callback"放在data里面
// jsonpcallback: "callback",
jsonpcallback: "fqniu",
},
// 回调函数 调用 callbackFun 函数
callback: callbackFun
})
function callbackFun(data) {
// console.log(data) // 拿到数据可以渲染
// 注意:当有些内容并没有被搜索 会返回undefined 所以需要判断这里
console.log(data.g)
let datas = data.g
if (datas) {
// 如果有搜索内容,则显示list
$(".list").style.display = "block"
} else {
// 如果没有搜索内容出现,则让list为none 并清除里面的内容
$(".list").style.display = "none"
$(".list").innerHTML = ""
// 退出函数,不执行下面的渲染页面内容
return false
}
// 渲染数据到页面
let html = ""
for (var i = 0; i < datas.length; i++) {
html += `<li>${datas[i].q}</li>`
}
$(".list").innerHTML = html
}
t = null
}, 500)
// 另一种写法 :ajax 和 promise 的封装函数 使用
t = setTimeout(function () {
// ajax 和 promise 的封装函数 使用
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: "hello world",
wd: ipt_value,
req: 2,
csor: 5,
cb: "fqniu",
_: Date.now(),
jsonpcallback: "fqniu"
}
})
.then(function (res) {
// console.log(res) // 拿到数据可以渲染
// 注意:当有些内容并没有被搜索 会返回undefined 所以需要判断这里
console.log(res.g)
let datas = res.g
if (datas) {
// 如果有搜索内容,则显示list
$(".list").style.display = "block"
} else {
// 如果没有搜索内容出现,则让list为none 并清除里面的内容
$(".list").style.display = "none"
$(".list").innerHTML = ""
// 退出函数,不执行下面的渲染页面内容
return false
}
// 渲染数据到页面
let html = ""
for (var i = 0; i < datas.length; i++) {
html += `<li>${datas[i].q}</li>`
}
$(".list").innerHTML = html
})
t = null
}, 500)
}
</script>
</body>
</html>
封装的ajax函数
utils.js文件
/**
* formate : 序列化 GET请求的 URL;
*
* formate( [ 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请求
*
* 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)
}
}
}
})
}
效果图如下
补充: jsonpcallback 调用部分
- jsonp发送请求时携带的数据是什么样的。
?key=value&key2=value2
- jsonp数据发送的时候一定会有一个选项告知后台应该使用什么样的全局函数名进行数据包裹
callback({"a" : 10 , "b" : 20})
-
jsonp 请求发送时一定会告知后端前端定义的全局函数名是什么。
-
前后端交互 , 前端发送数据需要的两个点: 1. 字段名; 2. 数据
-
两个接口分析 :
1. `https://api.gogoup.com/p1/data/recommend?type=0&pageNo=3&pageSize=5&fromId=546&jsonpcallback=callback&_= + Date.now()` 1. `jsonpcallback=callback1` 2. `https://www.baidu.com/sugrec?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=123&req=2&csor=5&pwd=hell&cb=callback2&_=1594630926722` 1. `cb=callback2`
-
封装核心思路 : 定义默认值, 放入data之中进行拼接。
//1. 定义默认参数 ;
function ajax(options){
options = Object.assign( {
// 字段名;
jsonp : "cb",
// 全局函数名;
jsonpcallback : "callback",
data : {}
}, options)
options.data[options.jsonp] = options.jsonpcallback;
//{ cb : callback}
}