highlight: a11y-dark
theme: nico
jQuery 是什么
- jQuery 本质:是一个快速,轻量级且功能丰富的 JavaScript 方法库,不是常说的前端框架,前端框架一般来说主要还是 VUE、React、Angular。
- jQuery 优点:选择器、隐式迭代、链式编程、解决兼容(jquery1功能,jquery3已经废弃),从而简化了HTML文档的 遍历、事件、动画和Ajax交互,从而实现了快速的Web开发
- jQuery 特色:一行代码,少写多做
- jQuery 官网:https://jquery.com/
jQuery 基本语法
$ 和 jQuery
- jQuery 对象: 在JavaScript文件中直接调用
- 调用方式:(1)$ (2)jQuery
$("selector").action();
// 1 $ 符号定义jQuery
// 2 "selector" 选择器匹配元素
// 3 action() 执行对元素的操作
$; //ƒ (e,t){return new ct.fn.init(e,t,V)}
jQuery; //ƒ (e,t){return new ct.fn.init(e,t,V)}
$ === jQuery; //true
typeof jQuery; //function
noConflict() 方法
- 需求场景:noConflict() 方法会释放对 $ 标识符的控制,这样其他使用 $ 的js脚本就可以使用了
- 解决办法:直接使用jQuery或者创建自己的简写,noConflict() 可返回对 jQuery 的引用,这样就可以把它存入变量,以供稍后使用
var jq = jQuery.noConflict();
jq(document).ready(function(){
jq("button").click(function(){
jq("p").text("jQuery 仍然在工作!");
});
});
//如果你的 jQuery 代码块使用 $ 简写,并且您不愿意改变这个快捷方式,那么您可以把 $ 符号作为变量传递给 ready 方法。这样就可以在函数内使用 $ 符号了 - 而在函数外,依旧不得不使用 "jQuery"
$.noConflict();
jQuery(document).ready(function($){
$("button").click(function(){
$("p").text("jQuery 仍然在工作!");
});
});
jQuery 入口函数
- jQuery 入口函数:在 html 所有标签(DOM)都加载之后,就会去执行。
- JavaScript 入口函数:window.onload 事件是等到所有内容,包括外部图片之类的文件加载完后,才会执行。
//jQuery 入口函数
$(document).ready(function(){ /*...*/ })
$(function(){ /*...*/ })
//JavaScript 入口函数
window.onload = function(){ /*...*/ }
jQuery 链式调用
jQuery Chaining:称为链技术,也叫做链式调用,该技术允许我们在一条语句中运行多个 jQuery 方法(在相同的元素上)。
//例:把 css()、slideUp() 和 slideDown() 链接在一起,p 元素先变红,后上滑,再然后下滑
$("p").css("color","red").slideUp(2000).slideDown(2000);
//可以换行和缩进,jQuery 会抛掉多余的空格,并当成一行长代码来执行上面的代码行
$("#p1").css("color","red")
.slideUp(2000)
.slideDown(2000);
jQuery 隐式迭代
jQuery 选择器
说明:jQuery 选择器返回伪数组,包含 length 属性,另外返回的参数分别是 context 和 selector,如果不是id选择器还包括 prevObject 对象。
1. 等同 CSS 的选择器
//同 CSS - 常用
$("*"); //-> 所有
$("#idName"); //-> id="idName"
$("div"); //-> 所有 div 标签
$(".intro,.demo"); //-> class 为 "intro" 或 "demo" 的所有元素
$("div:not(p)"); //-> div中所有非p的元素,但如果p没有设置样式也会受到影响
$(":root"); //-> 文档的根元素 html
$(":header"); //-> 所有 h1 - h6,但 h7-h9 也会匹配上
$("div > p"); // div 直接子元素的所有 p
$("div p"); // div 的所有后代 p
$("div + p"); // div 相邻的下一个 p,同jQuery的 next("p") 方法
$("div ~ p"); // div 同级的所有 p,同jQuery的 siblings("p") 方法
$("p:first-child"); //(所有元素中计数)-> 作为某个父元素的 第一个子元素(匹配满足这个条件的 第一个 p)
$("p:first-of-type"); //(所有元素中计数)-> 作为某个父元素的 第一个子元素(匹配满足这个条件的 所有 p)
$("p:last-child"); //(所有元素中计数)-> 作为某个父元素的 最后一个子元素(匹配满足这个条件的 第一个 p)
$("p:last-of-type"); //(所有元素中计数)-> 作为某个父元素的 最后一个子元素(匹配满足这个条件的 所有 p)
$("p:nth-child(2)"); //(所有元素中计数)-> 作为某个父元素的 第二个子元素(匹配满足这个条件的 所有 p)
$("p:nth-last-child(2)"); //(所有元素中计数)-> 作为某个父元素的 倒第二个子元素(匹配所有满足这个条件的 所有 p)
$("p:only-child"); //(所有元素中计数)-> 作为某个父元素的 p 元素(p是唯一的子元素,且只有一个)
$("p:nth-of-type(2)"); //(只在p元素中计数)-> 作为某个父元素的 所有第二个 p 元素
$("p:nth-last-of-type(2)"); //(只在p元素中计数)-> 作为某个父元素的 所有倒第二个 p 元素
$("p:only-of-type"); //(只在p元素中计数)-> 作为某个父元素的 那个唯一的 p 元素
$("p:lang(de)"); // 所有 lang 属性值为 "de" 的 p 元素
$("[href]"); // 所有带有 href 属性的元素
$("[href='default.htm']"); // 所有带有 href 属性且值等于 "default.htm" 的元素
$("[href!='default.htm']"); // 所有带有 href 属性且值不等于 "default.htm" 的元素
$("[href$='.jpg']"); // 所有带有 href 属性且值以 ".jpg" 结尾的元素
$("[title^='Tom']"); // 所有带有 title 属性且值以 "Tom" 开头的元素
$("[title|='Tomorrow']"); // 所有带有 title 属性且值等于 'Tomorrow' 或者以 'Tomorrow' 后跟连接符作为开头的字符串
$("[title~='hello']"); // 所有带有 title 属性且值包含单词 "hello" 的元素
$("[title*='hello']"); // 所有带有 title 属性且值包含字符串 "hello" 的元素
$("input[id][name$='man']"); // 带有 id 属性,并且 name 属性以 man 结尾的 input
$("a:link"); //-> 所有未访问链接
$("#news:target"); //-> 当前活动的#news元素(包含该锚名称的点击的URL)
$(":empty"); //-> 所有空元素(不含子元素或文本)
//同 CSS - 表单常用
$(":input"); //-> 所有 input 元素
$(":text"); //-> 所有带有 type="text" 的 input 元素
$(":password"); //-> 所有带有 type="password" 的 input 元素
$(":radio"); //-> 所有带有 type="radio" 的 input 元素
$(":checkbox"); //-> 所有带有 type="checkbox" 的 input 元素
$(":submit"); //-> 所有带有 type="submit" 的 input 元素
$(":reset"); //-> 所有带有 type="reset" 的 input 元素
$(":button"); //-> 所有带有 type="button" 的 input 元素
$(":image"); //-> 所有带有 type="image" 的 input 元素
$(":file"); //-> 所有带有 type="file" 的 input 元素
$("input:not(:empty)"); //-> 所有不为空的input
$(":focus"); //-> 当前 焦点的元素
$(":enabled"); //-> 所有启用的元素
$(":disabled"); //-> 所有禁用的元素
$(":selected"); //-> 所有选定的(option 具有 selected 属性)下拉列表元素
$(":checked"); //-> 所有选中的复选框选项
$("input:in-range") //标签的值在指定区间之外时显示的样式,例如 type="number" value="11" min="10" max="12
$("input:out-of-range");//标签的值在指定区间之外时显示的样式,例如 type="number" value="15" min="10" max="12
$("input:valid")//用于匹配输入值为合法的元素
$("input:invalid")//用于匹配输入值为非法的元素
$("input:optional")//用于匹配可选的输入元素
$("input:required")//匹配设置了 "required" 属性的元素
2. CSS 有效 Jquery 无效
//CSS 有效,jQuery无效
$(":visited"); //无效:选择所有访问过的链接
$(":active"); //无效:选择活动链接
$(":hover"); //无效:选择鼠标在链接上面时
$("p:first-letter"); //无效:所有 p 的第一个字母
$("p:first-line"); //无效:所有 p 的第一行1
$("p:before"); //无效:在每个<p>元素之前插入内容2
$("p:after"); //无效:在每个<p>元素之后插入内容
$("p::selection"); //无效 匹配元素中被用户选中或处于高亮状态的部分的属性 color, background, cursor,和outline
$("input:ready-write"); //无效 标签的值在指定区间之外时显示的样式,例如 type="number" value="15" min="10" max="12
$("input:ready-only"); //无效 标签的值在指定区间之外时显示的样式,例如 type="number" value="15" min="10" max="12
3. JQuery 特有
//jQuery 特有
$("p:first"); //-> 第一个 <p> 元素
$("p:last"); //-> 最后一个 <p> 元素
$("tr:even"); //-> 从 0 开始,所有偶数 tr 元素
$("tr:odd"); //-> 从 1 开始,所有奇数 tr 元素
$("p:eq(3)"); //-> 第4个p(从0开始计数)
$("p:gt(3)"); //-> 第3个之后的所有 p
$("p:lt(3)"); //-> 第3个之前的所有 p
$(":animated"); //-> 所有使用了animate()方法的动画元素,css定义的动画不匹配
$(":contains('ok')"); //-> 所有包含文本 "ok" 的元素
$("div:has(p)"); //-> 后代元素中包含 p 的 div
$(":parent"); //-> 所有非空元素(父元素,含有子元素或者文本,区别表单的空)
$("p:hidden"); //-> 所有隐藏的 p -> (隐藏指:display:none 或 type="hidden"表单,该选择器对 visibility:hidden 和 opacity: 0 的元素不起作用)
$("p:visible"); //-> 所有可见的 p -> (可见是非以下情况: (1)display:none (2)type="hidden" 表单 (3)width 和 height 设置为 0)
jQuery 遍历方法
jQuery 遍历,也称 jQuery DOM 遍历,意为”移动”,用于根据其相对于其他元素的关系来”查找/获取” HTML 元素,从这种功能上来看,非常类似于 jQuery 选择器。
遍历父类
parent()
- 功能:返回直接父级
- 语法:
$(selector).parent(filter)
parents()
- 功能:返回所有祖先元素,一路向上直到文档的根元素 html
- 语法:
$(selector).parents(filter)
parentsUntil()
- 功能:返回介于两个给定元素之间的所有祖先元素
- 语法:
$(selector).parentsUntil(filter)
$("p").parent(); //返回 p 的直接父级
$("p").parent(".selected"); //返回带有 selected 类的 p 的直接父元素
$("span").parents(); //返回所有 <span> 元素的所有祖先
$("span").parents("ul"); //返回所有 <span> 元素的所有祖先,并且它是 <ul> 元素
$("span").parentsUntil("div"); //返回介于 <span> 与 <div> 元素之间的所有祖先元素
遍历后代
children()
- 功能:返回被选元素的所有直接子元素
- 语法:
$(selector).children(filter)
find()
- 功能:返回与指定参数匹配的所有后代元素
- 语法:
$(selector).find(filter)
$("div").children(); //返回DIV的直接子元素
$("div").children("p"); //返回DIV的直接子代的所有<p>元素
$("p").find("span"); //返回属于 p 后代的所有 span 元素
$("div").find("*"); //返回 div 的所有后代
遍历同级
siblings()
- 功能:返回所有同级元素(selector如果是同一级,则不包含自身;selector如果是先指向父类,然后指向后代,则会返回所有)
- 语法:
$(selector).siblings(filter)
next() prev()
- 功能:next() 返回同级的下一个元素;prev()方向相反
- 语法:
$(selector).next(filter)
$(selector).prev(filter)
nextAll() prevAll()
- 功能:nextAll() 返回后面同级的所有元素;prevAll()方向相反
- 语法:
$(selector).nextAll(filter)
$(selector).prevAll(filter)
nextUntil() prevUntil()
- 功能:nextUntil() 返回介于两个给定参数之间的后面所有的同胞元素,prevUntil() 方向相反
- 语法:
$(selector).nextUntil(filter)
$(selector).prevUntil(filter)
$("h2").siblings();//返回 <h2> 的所有同胞元素
$("h2").siblings("p"); //返回属于 <h2> 的同胞元素的所有 <p> 元素
$("h2").next(); //返回 <h2> 的下一个同胞元素
$("h2").nextAll(); //返回 <h2> 的所有跟随的同胞元素
$("h2").nextUntil("h6"); //返回介于 <h2> 与 <h6> 元素之间(不包括 h2 和 h6)的所有同胞元素
<li>111</li> <li>222</li> <li>333</li> <li>444</li>
Array.from($("li").nextAll("li:nth-of-type(3)")).map(_=>_.innerText); // [333]
Array.from($("li").nextUntil()).map(_=>_.innerText); // [222,333,444] -> 从选择器的第二个开始到末尾
Array.from($("li:nth-of-type(1)").nextUntil("li:nth-of-type(3)")).map(_=>_.innerText); // [222]
Array.from($("li").prevAll()).map(_=>_.innerText); // [333,222,111] -> 从选择器的倒数第二个往上/往前,直到最上面/前面那个
Array.from($("li").prevUntil()).map(_=>_.innerText); // [333,222,111] -> 从选择器的倒数第二个往上/往前,直到给定选择器条件的下一个(如果不指定,则会到底)
Array.from($("li").prevUntil("li:nth-of-type(2)")).map(_=>_.innerText); // [333] -> 从选择器倒数第二个开始,往上/往前,直到给定选择器条件的最前面一个
过滤遍历
first() last()
- 功能:返回选择器指定的首个/最后一个元素(不包括selector自身)
- 语法:
$(selector).first(filter)
$(selector).last(filter)
eq()
- 功能:返回选择器指定的第n个元素,索引号从 0 开始
- 语法:
$(selector).eq(filter)
filter() not()
- 功能:filter 返回匹配的;not 返回不匹配的;具体规则可以自由指定
- 语法:
$(selector).filter(filter)
$(selector).not(filter)
- 说明:not() 方法与 filter() 相反。
$("li").first()[0].innerText; //111
$("li").last()[0].innerText; //444
$("li").eq(2)[0].innerText; //333
$("p").filter(".url"); //返回带有类名 "url" 的所有 <p> 元素
$("p").not(".url"); //返回不带有类名 "url" 的所有 <p> 元素
//not 和 eq 可以实现反选的效果,选取索引值不为 1 的 p 元素,并把背景颜色设置为黄色
$("p").not(":eq(1)").css("background-color","yellow");
jQuery HTML/CSS 方法
操作内容 text() html() val()
- html() – innerHTML 设置或返回所选元素的内容(包括 HTML 标签)
- text() – innerText 设置或返回所选元素的文本内容
- val() – value 设置或返回表单字段的值,返回第一个输入字段的值
- 回调函数的参数说明:以上三者都拥有回调函数,且有 两个参数
- 参数 1:被选元素列表中 当前元素的下标
- 参数 2:初始值
- 回调函数返回:一个字符串,相当于放在方法中设置的值
//获取
$("#test").text()); //等于 innerText
$("#test").html()); //等于 innerHTML
$("#test").val()); //获取表单 value
//设置
$("#test1").text("Hello world!");
$("#test2").html("<b>Hello world!</b>");
$("#test3").val("Hello world!");
//携带回调函数
<ul>
<li>111 <button>btn</button></li>
<li>222 <button>btn</button></li>
</ul>
$("li").text(function (index, originalText) {
return `第${index}个元素的初始值为${originalText},回调函数return的结果作为新值放在方法中`;
});
//页面更新为:
// 第0个元素的初始值为111 btn,回调函数return的结果作为新值放在方法中
// 第1个元素的初始值为222 btn,回调函数return的结果作为新值放在方法中
$("li").html(function (index, originalText) {
return `第${index}个元素的初始值为${originalText},回调函数return的结果作为新值放在方法中`;
});
//页面更新为:
// 第0个元素的初始值为111 btn(这个btn被解析成了元素),回调函数return的结果作为新值放在方法中
// 第1个元素的初始值为222 btn(这个btn被解析成了元素),回调函数return的结果作为新值放在方法中
<input type="text" value="10" />
<input type="text" value="11" />
$("input").val(function(index, originalText){
return(`第${index}个元素的初始值为${originalText},回调函数return的结果作为新值放在方法中`);
});
//页面input输入框的内容更新为回调函数的返回值
操作属性 attr() prop() removeAttr()
- attr() – 一般操作 自定义属性,但也能操作原生属性,只是不推荐
- prop() – 一般操作 原生属性,如果非要操作自定义属性,会把自定义属性添加到原生属性上,后面操作获取就是通过对象获取的
- removeAttr() – 移除属性,可使用字符串,如果移除多个属性,在一个字符串中用空格隔开,不能使用回调函数
- 回调函数的参数说明:attr() prop() 都拥有回调函数,且有 两个参数
- 参数 1:被选元素列表中 当前元素的下标
- 参数 2:初始值
- 回调函数返回:一个字符串,相当于放在方法中设置的值,这个回调函数是逐个地对集合元素采取操作,如果是要获取整个集合,把每个元素组合起来当成整理看待,则需要跳出这个函数外,再从第三方进行操作(见示例-多行关键词菜单)
//设置和获取自定义属性
$("input").attr("data-index","0");
$("input").attr("data-index"); // 0 当该方法用于**返回**属性值,只返回第一个匹配元素的值
$("input").attr("data-empty"); // undefined 不存在的属性返回 undefined
$("a").attr({
"data-href" : "http://jquery.com",
"data-index" : "0" }
);
$("a").attr("data-href", function(index,origValue){
return origValue + "/jquery";
});
//设置和获取原生属性
//说明:与DOM中setAttribute()不同的是,prop("disabled",true/false) 有效
t($("input").prop("disabled",true)); //禁止有效
t($("input").prop("disabled")); //true 返回第一个匹配元素的值
t($("input").prop("disabled",false)); //解禁有效
t($("input").prop("disabled")); //false
$("input").prop("disabled",function(index, originalValue){
console.log(`第${index}个元素的初始值为${originalValue},回调函数return的结果作为新值放在方法中`);
return true;
});
//页面结果:input被禁用了
//移除属性
$("input").removeAttr("min max"); //解除input的输入限制
操作节点 append() prepend() after() before() remove() empty() clone()
- append() – 在被选元素的结尾插入内容(元素内部)
- prepend() – 在被选元素的开头插入内容(元素内部)
- after() – 在被选元素之后插入内容(元素外面)
- before() – 在被选元素之前插入内容(元素外面)
- remove() – 删除被选元素(及其子元素),扔掉桶的做法,可传参实现过滤删除
- empty() – 从被选元素中删除子元素,倒掉水的做法
- clone() – 方法生成被选元素的副本,包含子节点、文本和属性
//append() 和 prepend() 方法能够通过参数接收无限数量的新元素
function appendText(){
var txt1="<p>文本-1</p>"; // 使用 HTML 标签创建文本
var txt2=$("<p></p>").text("文本-2"); // 使用 jQuery 创建文本
$("body").append(txt1,txt2,"<p>文本-3</p>"); // 追加新元素
}
//after() 和 before() 方法能够通过参数接收无限数量的新元素
function afterText() {
var txt1="<b>I </b>"; // 使用 HTML 创建元素
var txt2=$("<i></i>").text("love "); // 使用 jQuery 创建元素
$("img").after(txt1,txt2,"<b>you</b>"); // 在图片后添加文本
}
//删除
$("#div1").remove(); //删除被选元素及其子元素
$("p").remove(".italic"); //过滤:删除除了类名为italic的p元素,remove是删除自身,因此过滤器中条件只能作用于同级,不能作用于子元素
$("#div1").empty(); //删除被选元素的子元素
//复制
$("body").append($("p:first").clone(true)); //true 复制事件处理程序,alse(默认)不复制事件处理程序
操作样式 css() addClass() removeClass() toggleClass()
- css() – 设置或返回样式属性
- addClass() – 向被选元素添加一个或多个类
- removeClass() – 从被选元素删除一个或多个类
- toggleClass() – 对被选元素进行添加/删除类的切换操作
- hasClass() – 判断是否包含某个类(如果是多个元素,只要有一个满足就返回 true)
- 说明:
- css() 方法:样式都添加在行内属性;具有隐式迭代功能。例如,选中多个元素,会自动给每个设置好样式
- css() 方法:不能直接设置部分伪类伪元素样式,可通过
$(选择器).append("<style>选择器::after{display:none}</style>");
方式间接实现 - 操作class:操作class 的方法,添加到class中定义的属性,因此相比于css将属性添加到行内,权重更低
//获取和设置 css 样式
$("p").css("background-color");
$("p").css("background-color","yellow");
$("p").css({
"background-color":"yellow",
"font-size":"200%"
});
$("div").css({
width:"-=30px",
height:"+=10px" //可以取相对值,在原来的基础上增加或减少
});
//添加多个类
$("body div:first").addClass("important blue");
//第一个参数表示要添加或删除的类,既可以用类列表,也可以用函数返回值指定(i 是选择器选中的所有元素中当前对象的索引值,c 是当前对象的类名)
// switch: 布尔值,true 表示只添加,false 表示只删除
$("body div:first").addClass('c1 c2 ...' | function(i, c)); // 添加一个或多个类
$("body div:first").removerClass('c1 c2 ...' | function(i, c)); // 删除一个或多个类。
$("body div:first").toggleClass('c1 c2 ...' | function(i, c), switch); // 切换一个或多个类
操作尺寸 width() innerWidth() outerWidth()
- width() height() – content:设置或返回元素的宽/高(不包括内边距、边框或外边距),类似DOM中的offsetWidth offsetHeight,但在display:none;时,依然能获取到
- innerWidth() innerHeight() – content+padding:返回元素的宽高(包括内边距),类似DOM中的clientWidth clientHeight
- outerWidth() outerHeight() – content+padding+border:返回元素的宽高(包括内边距和边框)
- outerWidth(true) outerHeight(true) – content+padding+border+margin:返回元素的宽高(包括内边距、边框和外边距)
- 注意:如果设置了 box-sizing 后,width() 获取的是 css 设置的 width 减去 padding 和 border 的值
$("li").width();
$("li").eq(1).height();
//对于设置了 box-sizing
//.test{width:100px;height:100px;padding:10px;border:10px;box-sizing:border-box;}
$(".test").width(); // 60
$(".test").innerWidth(); // 80
$(".test").outWidth(); // 100
操作布局 offset() position()
- offset() – 获取距离文档流左上角的left、top,如果传参数就是设置,相当于是在行内添加了一个relative的相对定位样式
- position() – 有定位的元素的left、top(相对于它的父元素),只能获取不能设置,该方法返回一个带有两个属性(以像素为单位的 top 和 left 位置)的对象
- 说明:如果有多个元素,只获取第一个
//返回偏移坐标:$(*selector*).offset()
$("p").offset();
//设置偏移坐标:$(*selector*).offset({top:*value*,left:*value*})
newPos=new Object();
newPos.left="0";
newPos.top="100";
$("p").offset(newPos);
//使用函数设置偏移坐标:$(*selector*).offset(function *(index,currentoffset)* )
$("p").offset(function(n,c){
newPos=new Object();
newPos.left=c.left+100;
newPos.top=c.top+100;
return newPos;
});
//获取 <p> 元素在 <div> 元素内部的位置
<div style="border:1px solid black;padding:100px;margin:50px;">
<p>这一段的位置(相对于它的父元素)是<span id="span1">x</span> top 和 <span id="span2">x</span> left.</p>
</div>
x=$("p").position();
$("#span1").text(x.top);
$("#span2").text(x.left);
jQuery 效果方法
隐藏显示 1 – 闪现 hide() show() toggle()
- 功能:hide() – 隐藏;show() – 显示;toggle() – 切换;底层以
display:none/block;
实现 - 语法:
$(*selector*).hide(speed,timing-function,callback);
- 可选参数 speed:隐藏/显示的速度,可以三类值:slow、fast、毫秒
- 可选参数 timing-function:字符串,效果过渡类型,只能取值 linear ,其它报错
- 可选参数 callback:隐藏或显示完成后所执行的函数,如果调用callback时,在函数名后直接加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行,而且只会 执行一次,只有当作回调参数的时候才会有多个元素而 执行多次
$("div").hide(1000,"linear",function(){
alert("Hide() 方法已完成!");
});
隐藏显示 2 – 淡入 fadeOut() fadeIn() fadeToggle() fadeTo()
- 功能:fadeOut() – 淡出;fadeIn() – 淡入;fadeToggle() – 切换;fadeTo() – 指定渐变;底层以
display:none/block;
和opacity:[number];
实现 - 语法:
$(*selector*).fadeToggle(*speed,callback*);
$(*selector*).fadeTo(speed,opacity,callback);
- 参数:fadeTo() 没有默认参数,必须加上 slow/fast/Time
- 可选参数 speed:隐藏/显示的速度,可以三类值:slow、fast、毫秒
- 可选参数 opacity:fadeTo() 方法,表示给定的不透明度(值介于 0 与 1 之间)
- 可选参数 callback:隐藏或显示完成后所执行的函数,如果调用callback时,在函数名后直接加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行,而且只会 执行一次,只有当作回调参数的时候才会有多个元素而 执行多次
$("li").hide("fast");
$("li").show(100);
$("#div3").fadeTo("slow",0.7);
隐藏显示 3 – 滑动 slideDown() slideUp() slideToggle()
- 功能:slideDown() – 下滑;slideUp() – 上滑;slideToggle() – 切换;底层以
display:none/block;
和opacity:[number];
实现 - 语法:
$(*selector*).slideToggle(*speed,callback*);
- 可选参数 speed:隐藏/显示的速度,可以三类值:slow、fast、毫秒
- 可选参数 callback:隐藏或显示完成后所执行的函数,如果调用callback时,在函数名后直接加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行,而且只会 执行一次,只有当作回调参数的时候才会有多个元素而 执行多次
$("#panel").slideToggle();
动画效果 – animate()
- 功能:创建自定义动画
- 语法:
$(*selector*).animate({params},speed,callback);
- 必需的 params 参数:定义形成动画的 CSS 属性
- 可选的 speed 参数:规定效果的时长,取值:”slow”、”fast” 或毫秒
- 可选的 callback 参数:是动画完成后所执行的函数名称
- 属性名:当使用 animate() 时,必须使用 Camel 标记法书写所有的属性名,比如,必须使用 paddingLeft 而不是 padding-left,使用 marginRight 而不是 margin-right,等等。
- 颜色插件:色彩动画并不包含在核心 jQuery 库中,如需生成颜色动画,需要从 jquery.com 下载 颜色动画 插件。
- 相对值:在值的前面加上 += 或 -=
- 预定义值:把属性的动画值设置为 “show”、”hide” 或 “toggle”
//把 <div> 元素往右边移动 250px
$("div").animate({left:'250px'});
//动画使用多个属性
$("div").animate({ left:'250px', opacity:'0.5', height:'150px', width:'150px' });
//动画可以定义相对值(该值相对于元素的当前值)。需要在值的前面加上 += 或 -=
$("div").animate({ left:'250px', height:'+=150px', width:'+=150px' });
//预定义值:把属性的动画值设置为 "show"、"hide" 或 "toggle"
$("div").animate({ height:"toggle" });
//动画队列:如果在彼此之后编写多个 animate() 调用,jQuery 会创建包含这些方法调用的"内部"队列,然后逐一运行这些 animate 调用
var div=$("div");
div.animate({height:'300px',opacity:'0.4'},"slow"); div.animate({width:'300px',opacity:'0.8'},"slow"); div.animate({height:'100px',opacity:'0.4'},"slow"); div.animate({width:'100px',opacity:'0.8'},"slow");
div.animate({left:'100px'},"slow");
div.animate({fontSize:'3em'},"slow");
停止动画 – stop()
- 功能:停止动画
- 语法:
$(*selector*).stop(stopAll,goToEnd);
- 可选 stopAll 参数:规定是否应该清除动画队列。默认是 false(仅停止活动的动画,允许任何排入队列的动画向后执行)
- 可选 goToEnd 参数:规定是否立即完成当前动画。默认是 false(不立即完成)
$("#panel").stop(); //动画中途暂停,还可以继续执行
$("#panel").stop(true); //队列中的动画都清除,动画中途结束,不可继续执行
$("#panel").stop(false,true); //当前动画立即完成,后续队列不清除,还可继续执行
//stop() 停止动画 -> 可用于模拟防抖
ele.stop().toggle();
jQuery 事件方法
- ready() – 规定当 DOM 完全加载时要执行的函数
- on() – 绑定事件
- off() – 解绑事件
- one() – 一次性事件,触发后立即解绑
- 说明:都具有隐式迭代;具体事件方法同 DOM
$(this)
:JQuery 中 this 一般用$(this)
代替,因为this.innerHTML 跟$(this)
.html() 的结果是一致的- 同时给多个元素绑定事件:
$(".brand-detail li,.size-detail li,.color-detail li").on( ... )
/* 绑定事件 on() */
$("li").on("click",_=> console.log(_.target));
//事件委托,第二个参数表示指定冒泡到哪一个节点(只触发这个节点)
$("ul").on("click","button",function(){ console.log(this); }); //this 的结果是 button节点
//事件参数,如果第二个往后的参数是字符串,则默认是冒泡触发事件的一个元素,如果传入的是对象,则认为是作为事件函数的参数
$("ul").on("click","button",{ result:"this is button" },function(e){
console.log(e.data.result, this);
});
/* 解绑事件 off() */
$("ul").off("click"); //移除 click 事件
$("ul").off(); //移除所有的事件
$("ul").off("input",funcA); //解绑链式绑定中指定的一个
/* 触发一次 one() */
$("ul").one("click","button",{ result:"this is button" },function(e){
console.log(e.data.result, this);
})
//链式绑定
$("button").click({arg:"something"},function(){
console.log("clicked");
}).mouseout(function(){
console.log("moved out");
})
$("input").on("input",function funcA(e){
console.log($("input")[0].value);
}).on("input",{inputText:`${$("input")[0].value}`},function funcB(e){
console.log(e.data.inputText);
});
jQuery Ajax 方法
$.ajax()
- 语法:
$.ajax( {name:value, name:value, ... } )
- 参数如下
名称 | 值/描述 |
---|---|
async | 布尔值,表示请求是否异步处理。默认是 true。 |
beforeSend(xhr) | 发送请求前运行的函数。 |
cache | 布尔值,表示浏览器是否缓存被请求页面。默认是 true。 |
complete(xhr,status) | 请求完成时运行的函数(在请求成功或失败之后均调用,即在 success 和 error 函数之后)。 |
contentType | 发送数据到服务器时所使用的内容类型。默认是:”application/x-www-form-urlencoded”。 |
context | 为所有 AJAX 相关的回调函数规定 “this” 值。 |
data | 规定要发送到服务器的数据。 |
dataFilter(data,type) | 用于处理 XMLHttpRequest 原始响应数据的函数。 |
dataType | 预期的服务器响应的数据类型。 |
error(xhr,status,error) | 如果请求失败要运行的函数。 |
global | 布尔值,规定是否为请求触发全局 AJAX 事件处理程序。默认是 true。 |
ifModified | 布尔值,规定是否仅在最后一次请求以来响应发生改变时才请求成功。默认是 false。 |
jsonp | 在一个 jsonp 中重写回调函数的字符串。 |
jsonpCallback | 在一个 jsonp 中规定回调函数的名称。 |
password | 规定在 HTTP 访问认证请求中使用的密码。 |
processData | 布尔值,规定通过请求发送的数据是否转换为查询字符串。默认是 true。 |
scriptCharset | 规定请求的字符集。 |
success(result,status,xhr) | 当请求成功时运行的函数。 |
timeout | 设置本地的请求超时时间(以毫秒计)。 |
traditional | 布尔值,规定是否使用参数序列化的传统样式。 |
type | 规定请求的类型(GET 或 POST)。 |
url | 规定发送请求的 URL。默认是当前页面。 |
username | 规定在 HTTP 访问认证请求中使用的用户名。 |
xhr | 用于创建 XMLHttpRequest 对象的函数。 |
//高德API获取天气情况
$.ajax({
url:"https://restapi.amap.com/v3/weather/weatherInfo",
method:"get",
data:{
key:"429951164744f19f085244582f537008",
city:"成都",
extensions:"all"
},
dataType:"json",
success:function(result, status, xhr){
result.forecasts[0].casts.forEach(item=>{console.log(`数据获取:${status} 成都 ${item.date} 天气 ${item.dayweather} 温度 ${item.daytemp}`)});
//数据获取:success 成都 2022-11-21 天气 多云 温度 19
//数据获取:success 成都 2022-11-22 天气 多云 温度 19
//数据获取:success 成都 2022-11-23 天气 多云 温度 15
//数据获取:success 成都 2022-11-24 天气 阴 温度 19
},
error:function(xhr, status, error){
console.log(status); //error
console.log(error); //Not Found
}
});
$.get()
两种在客户端和服务器端进行请求-响应的常用方法是:GET 和 POST,具体区别见 详解
- 语法:
$.get(URL,callback);
或$.get( URL, data, callback, dataType)
- 参数 URL:请求的服务端地址
- 可选参数 data:发送给服务器的字符串或 key/value 键值对对象
- 可选参数 callback:请求成功后执行的回调函数;callback 参数包含三种:responseTxt – 结果内容;statusTXT – 调用状态;xhr – XMLHttpRequest 对象
- 可选参数 dataType:从服务器返回的数据类型。例如:xml, json, script, html
$.get("http://localhost:3000/list","name=James",function(responseText,statusText){
console.log(responseText,statusText);
},"html");
//以html格式回传:
// [
// {
// "name": "James",
// "age": 18
// }
// ] success
jQuery.get("http://localhost:3000/list",{name:"James"},function(responseText,statusText){
console.log(responseText,statusText);
},"json");
//以json格式回传:
//[{…}]0 age: 18name: "James" 'success'
//json 文件
{
"list": [
{
"name": "James",
"age": 18
}
]
}
$.post()
- 语法:
$.post(URL,callback);
或$.post( URL, data, callback, dataType)
- 参数 URL:请求的服务端地址
- 可选参数 data:发送给服务器的字符串或 key/value 键值对对象
- 可选参数 callback:请求成功后执行的回调函数;callback 参数包含三种:responseTxt – 结果内容;statusTXT – 调用状态;xhr – XMLHttpRequest 对象
- 可选参数 dataType:从服务器返回的数据类型。例如:xml, json, script, html
$.post("http://localhost:3000/list","name=James",function(responseText,statusText){
console.log(responseText,statusText);
},"html");
//以html格式回传:
// {
// "name": "James",
// "id": 1
// } success
jQuery.post("http://localhost:3000/list",{name:"James"},function(responseText,statusText){
console.log(responseText,statusText);
},"json");
//以json格式回传:
//{name: 'James', id: 2} 'success'
//json 文件
{
"list": [
{
"name": "James",
"age": 18,
"id": 0
//如果不定义id,post可能报错 TypeError: Cannot read properties of undefined (reading 'id)
},
{
"name": "James",
"id": 1
},
{
"name": "James",
"id": 2
}
]
}
')
load() 加载
- load() – 从服务器 加载数据,并把返回的数据 放入被选元素
- 语法 –
$(selector).load(URL,data,callback);
- 参数 URL – 获取参数的服务端地址,也可以是文件或锚点
- 参数 data – 查询键/值字符串
- 参数 callback – load() 方法完成后所执行的函数名称
- callback 参数 包含三种:responseTxt – 结果内容;statusTXT – 调用状态;xhr – XMLHttpRequest 对象
<body>
<button>btn</button>
<b id="target">btn</b>
<div></div>
</body>
//从服务端加载数据,放入元素
$("div").load("http://localhost:3000/list","name=James")
//从文件加载数据,放入元素
$("div").load("test.html")
//从文件锚点加载数据,放入元素,把 test.html 中id为target的元素即内容,加载到div中
$("div").load("test.html #target")
//callback 参数
$("#div1").load("test.html",function(responseTxt,statusTxt,xhr){
if(statusTxt=="success") alert("外部内容加载成功!");
if(statusTxt=="error") alert("Error: "+xhr.status+": "+xhr.statusText);
});
ajaxStop() 方法
ajaxStop() 方法规定所有的 AJAX 请求完成时运行的函数。
当 AJAX 请求完成时,jQuery 会检查是否存在更多的 AJAX 请求。如果没有其他请求正在等待运行,ajaxStop()方法会运行指定的函数。
注意: 自 jQuery 版本 1.8 起,该方法只被附加到文档。
当所有 AJAX 请求完成时,触发一个提示框:
$(document).ajaxStop(function())
$(document).ajaxStop(function(){ alert(“所有 AJAX 请求已完成”); });
jQuery 延迟方法 when
如何等待ajax完成再执行相应操作,基本的办法可以通过status状态码来判断, 但是这样以来 status 的值在ajax 请求成功之后进行 if 判断的时候值仍然为 false。因为 ajax 有个 async 属性,该属性默认为 true,表示 ajax 异步执行,而在进行 if 判断的时候,ajax 的异步执行还没完成,因此 status 的值仍然是 false。若要保证 status 的值是在 ajax 执行完成之后的最终值,有两种办法:1、将 ajax 的 async 属性设置为 false,表示 ajax 同步执行。2、利用 jquery 的 when().done 函数 等待 ajax 执行结束之后再进行后续操作。
var statusVal;
$.ajax({
url: "http://localhost:3000/size",
method: "get",
dataType: "json",
data: {},
success: function (result, status) {
result.forEach(item => {
$(".brand-detail").append(`<li>${item.content}</li>`)
});
statusVal = status;
console.log(statusVal); //true
}
})
// 根据 status 的状态 进行后续操作
function(){
if(statusVal){ //false
// 后续操作
}
}
var statusVal;
var aj = $.ajax({
url: "http://localhost:3000/size",
method: "get",
dataType: "json",
data: {},
success: function (result, status) {
result.forEach(item => {
$(".brand-detail").append(`<li>${item.content}</li>`)
});
statusVal = status;
console.log(statusVal); //true
}
})
// 根据 statusVal 后续操作
function(){
// myajax 请求完毕时执行
$.when(aj).done(function(){
if(statusVal){
// 后续操作
}
}) ;
}
示例
Accordion 手风琴效果
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
</head>
<body>
<nav class="container">
<div class="title">
<div class="slogon">◷</div>
<p>web class</p>
<i class="down">
<narrow></narrow>
</i>
</div>
<ul class="ul-1">
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
</ul>
<div class="title">
<div class="slogon">◶</div>
<p>web class</p>
<i class="down">
<narrow></narrow>
</i>
</div>
<ul class="ul-2">
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
</ul>
<div class="title">
<div class="slogon">◵</div>
<p>web class</p>
<i class="down">
<narrow></narrow>
</i>
</div>
<ul class="ul-3">
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
</ul>
<div class="title">
<div class="slogon">◴</div>
<p>web class</p>
<i class="down">
<narrow></narrow>
</i>
</div>
<ul class="ul-4">
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
<li>photoshop</li>
</ul>
</nav>
</body>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script>
//suite mobile
$(document).ready(function () {
$("*").css({ margin: 0, padding: 0 });
$("html").css("font-size", `${$("html")[0].clientWidth / 375 * 100}px`);
//JQuery 实现手风琴效果
$(".container").css({
width: "80vw",
height: "70vh",
border: "1px solid black",
margin: "10vh auto",
overflow: "auto"
})
$(".container>div").css({
display:"table",
width: "100%",
height: "5%",
fontSize: "0.15em",
cursor: "pointer"
}).on("mouseover", function () {
$(this).css("color", "red")
}).on("mouseout", function () {
$(this).css("color", "black")
}).on("click", function () {
$(this).siblings("ul").slideUp(500);
//箭头向上
$(this).siblings("ul").prev().find("narrow").css({
transition:"all 1s 0s ease-in",
transform:"rotate(0deg)",
transformOrigin:"center"
});
//点击的如果是同一元素,需要判断该元素是处于打开还是关闭的状态,否则,切换时将会处于反复打开的问题
if ($(this).next("ul").css("display") == "none") {
$(this).next("ul").slideDown(500);
$(this).css("color", "red")
console.log($(this).children("narrow"))
//箭头向下
$(this).find("narrow").css({
transition:"all 1s 0s ease-in",
transform:"rotate(-180deg)",
transformOrigin:"center"
});
} else {
$(this).next("ul").slideUp(500); //height变化时,display会自动设置成了block,等到变化结束,就会又回到none
//箭头向上
$(this).find("narrow").css({
transition:"all 1s 0s ease-in",
transform:"rotate(0deg)",
transformOrigin:"center"
});
}
});
$(".container .slogon").css({
width:"5%",
height: "100%",
fontSize: "0.5em",
display:"table-cell",
textAlign: "center",
verticalAlign:"middle"
});
$(".container p").css({
width:"90%",
height: "100%",
fontSize: "0.5em",
display:"table-cell",
verticalAlign:"middle"
});
$(".container .down").css({
width:"5%",
height: "100%",
display:"table-cell",
textAlign: "center",
verticalAlign:"middle"
})
$(".container .down narrow").css({
display: "inline-block",
width:"0.05rem",
height: "0.05rem",
backgroundColor:"black",
clipPath:"polygon(50% 0%, 100% 100%, 50% 50%,0 100%)"
})
$(".container>ul").css({
width: "100%",
listStyleType: "none",
textIndent: "0.1rem",
display:"none",
backgroundColor: "black",
color: "white"
})
$(".container li").css({
height: "0.1rem",
lineHeight: "0.1rem",
fontSize: "0.05rem"
}).on("mouseover", function () {
$(this).css({
backgroundColor: "white",
color: "black"
})
}).on("mouseout", function () {
$(this).css({
backgroundColor: "black",
color: "white"
})
})
})
</script>
</html>
关键词菜单选项卡 version 1.0
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<style>
.each-title {
width: 20%;
display: inline-block;
float: left;
text-align: center;
border-bottom: 1px solid orange;
font-size: 0.8rem;
line-height: 1.8rem;
}
.each-item {
width: 10%;
display: inline-block;
text-align: center;
border-radius: 5px;
font-size: 0.8rem;
line-height: 1.8rem;
list-style-type: none;
margin: 1rem;
}
.each-item-hover {
background-color: orange;
color: white;
cursor: pointer
}
.result-detail-initial {
color: gray;
font: italic lighter 0.6rem/1.5rem Aria;
}
</style>
</head>
<body>
<section class="container">
<div class="brand">
<span>品牌</span>
<ul class="brand-detail">
<li>全部</li>
</ul>
</div>
<div class="size">
<span>尺寸</span>
<ul class="size-detail">
<li>全部</li>
</ul>
</div>
<div class="color">
<span>颜色</span>
<ul class="color-detail">
<li>全部</li>
</ul>
</div>
<div class="result">
<span>筛选</span>
<ul class="result-detail">
<span class="result-detail-initial">暂未选择筛选条件...</span>
</ul>
</div>
</section>
</body>
<script>
var statusVal;
//ajax 初始化“品牌”
var iAjax = $.ajax({
url: "http://localhost:3000/brand",
method: "get",
dataType: "json",
data: {},
success: function (result, status) {
result.forEach(item => {
$(".brand-detail").append(`<li>${item.content}</li>`)
});
statusVal = status;
},
error: function (xhr, status, error) {
console.log(status + error);
}
})
//ajax 初始化“尺寸”
var iAjax = $.ajax({
url: "http://localhost:3000/size",
method: "get",
dataType: "json",
data: {},
success: function (result, status) {
result.forEach(item => {
$(".size-detail").append(`<li>${item.content}</li>`)
});
statusVal = status;
},
error: function (xhr, status, error) {
console.log(status + error);
}
})
//ajax 初始化“颜色”
var iAjax = $.ajax({
url: "http://localhost:3000/color",
method: "get",
dataType: "json",
data: {},
success: function (result, status) {
result.forEach(item => {
$(".color-detail").append(`<li>${item.content}</li>`)
});
statusVal = status;
},
error: function (xhr, status, error) {
console.log(status + error);
}
})
//ajax页面渲染完毕再执行后续
$.when(iAjax).done(function () {
if (statusVal == "success") {
$("*").css({ margin: "0", padding: "0" });
//适配移动端
$("html").css("font-size", `${$("html").innerWidth() / 375 * 10}px`);
//外框
$(".container").css({ width: "80vw", display: "block", margin: "2rem auto", padding: "0 1rem", border: "1px solid black" });
//每一行
$(".container>div").css({ margin: "1rem auto", overflow: "auto" });
//标题
$("span:not(:last-child)").addClass("each-title");
//项目
$("li:first-of-type").addClass("each-item-hover");
$("li").addClass("each-item").hover(function () {
//移入项目,先取消全部背景,然后加上背景orange
$(this).parent().find("li:first-of-type").removeClass("each-item-hover");
$(this).addClass("each-item-hover");
}, function () {
//移出项目,如果选项卡都没有被选中,就恢复“全部”选项卡的初始class
$(this).removeClass("each-item-hover");
//-------------------attr()方法的回调函数-----------------------
var hasChosen = 0; //第三方变量,判断一行中的选项卡是否有被选中的,不能在attr()方法的回到函数中定义,否则每次遍历都会重新声明
$(this).parent().children("li").attr("data-chosen", function (i, origValue) {
origValue === "chosen" ? hasChosen = 1 : null;
});
!hasChosen ? $(this).parent().children("li:first-of-type").addClass("each-item-hover") : null;
//----------------------------------------------------
}).on("click", function (e) {
//点击项目,自定义属性标记项目是否选中
$(this).parent().children("li").css({ backgroundColor: "", color: "" }).removeAttr("data-chosen");
e.target.innerText !== "全部" ? $(this).css({ backgroundColor: "orange", color: "white" }).attr("data-chosen", "chosen") : null;
//自定义是否选中,同时定义一个属性标识属于哪一行
if ($(this).parent().hasClass("brand-detail")) {
$(this).attr("data-brand", "brand");
} else if ($(this).parent().hasClass("size-detail")) {
$(this).attr("data-size", "size");
} else if ($(this).parent().hasClass("color-detail")) {
$(this).attr("data-color", "color");
} //else none
//获取每一行选中的项目
if ($(this).parent().hasClass("brand-detail")) {
$(".result-detail").find("[data-brand='brand']").remove();
if (e.target.innerText !== "全部") {
var newBrandBlock = $(this).clone().css({ width: "12%", margin: "auto 0.1rem" }).append("<span> ×</span>").on("click", function () {
$(this).remove();
$(".brand-detail").children().css({ backgroundColor: "", color: "" });
$(".brand-detail").children(":first").css({ backgroundColor: "orange", color: "white" });
});
$(".result-detail").append(newBrandBlock);
} //else none
} else if ($(this).parent().hasClass("size-detail")) {
$(".result-detail").find("[data-size='size']").remove();
if (e.target.innerText !== "全部") {
var newSizeBlock = $(this).clone().css({ width: "12%", margin: "auto 0.1rem" }).append("<span> ×</span>").on("click", function () {
$(this).remove();
$(".size-detail").children().css({ backgroundColor: "", color: "" });
$(".size-detail").children(":first").css({ backgroundColor: "orange", color: "white" });
});
$(".result-detail").append(newSizeBlock);
} //else none
} else if ($(this).parent().hasClass("color-detail")) {
$(".result-detail").find("[data-color='color']").remove();
if (e.target.innerText !== "全部") {
var newColorBlock = $(this).clone().css({ width: "12%", margin: "auto 0.1rem" }).append("<span> ×</span>").on("click", function () {
$(this).remove();
$(".color-detail").children().css({ backgroundColor: "", color: "" });
$(".color-detail").children(":first").css({ backgroundColor: "orange", color: "white" });
});
$(".result-detail").append(newColorBlock);
} //else none
} //else none
});
//筛选结果显示值
var unChosenText = $(".result-detail-initial").text();
var unChosenClassName = "result-detail-initial";
$("html").on("click", function () {
//jQuery 颜色使用rgb作为返回值
var brandFirstBack = $(".brand").find("li:first").css("background-color");
var sizeFirstBack = $(".size").find("li:first").css("background-color");
var colorFirstBack = $(".color").find("li:first").css("background-color");
if (brandFirstBack === "rgb(255, 165, 0)" && brandFirstBack === sizeFirstBack && sizeFirstBack === colorFirstBack) {
!$(".result-detail").children().hasClass("result-detail-initial") ? $(".result-detail").append(`<span class="${unChosenClassName}">${unChosenText}</span>`) : null;
} else {
$(".result-detail-initial").remove();
}
})
}
})
</script>
</html>
{
"brand": [
{"id": 0,"content": "小米"},
{"id": 1,"content": "华为"},
{"id": 2,"content": "oppo"},
{"id": 3,"content": "vivo"}
],
"size": [
{"id": 0,"content": "1060"},
{"id": 1,"content": "960"},
{"id": 2,"content": "680"},
{"id": 3,"content": "375"}
],
"color": [
{"id": 0,"content": "红色"},
{"id": 1,"content": "黑色"},
{"id": 2,"content": "绿色"},
{"id": 3,"content": "蓝色"},
{"id": 4,"content": "银灰"}
]
}
关键词菜单选项卡 version 2.0
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<style>
*{ margin:0; padding:0}
.each-title {width: 15%;margin:auto 1rem;display: block;float: left;text-align: center;border-bottom: 1px solid orange;font-size: 0.8rem;line-height: 1.8rem;}
.each-item {width: 10%;display: inline-block;text-align: center;border-radius: 5px;font-size: 0.8rem;line-height: 1.8rem;list-style-type: none;}
.each-item-hover {background-color: orange;color: white;cursor: pointer}
.result-detail-initial {color: gray;font: italic lighter 0.6rem/1.5rem Aria;}
</style>
</head>
<body>
<section class="container">
<div class="brand">
<span>品牌</span>
<ul class="brand-detail">
<li>全部</li>
</ul>
</div>
<div class="size">
<span>尺寸</span>
<ul class="size-detail">
<li>全部</li>
</ul>
</div>
<div class="color">
<span>颜色</span>
<ul class="color-detail">
<li>全部</li>
</ul>
</div>
<div class="result">
<span>筛选</span>
<ul class="result-detail">
<span class="result-detail-initial">暂未选择筛选条件...</span>
</ul>
</div>
</section>
</body>
<script>
//初始化页面
var statusValue; //判断是否响应完成
function ajaxFun(parameters,selector){
$.ajax({
url:`http://localhost:3000/${parameters}`,
method:"get",
data:{}, //取回所有数据
dataType:"json",
success:function(result,status){
statusValue = status; //如果相应完成且成功,status 的结果即为 success
result.forEach( item => {
$(selector).append(`<li>${item.content}</li>`);
});
},
error:function(xhr,status,error){
console.log(status + " : " + error);
}
})
}
var ajaxBrand = ajaxFun("brand",".brand-detail"); //ajax 初始化“品牌”
var ajaxSize = ajaxFun("size",".size-detail"); //ajax 初始化“尺寸”
var ajaxColor = ajaxFun("color",".color-detail"); //ajax 初始化“颜色”
//ajax页面渲染完成再执行后续
$(document).ajaxStop(function () {
if (statusValue == "success") {
//基本样式
$("html").css("font-size", `${$("html").innerWidth() / 375 * 10}px`); //适配移动端
$(".container").css({ width: "80vw",margin:" 1rem auto",padding: "1rem",boxShadow:"2px 2px 5px", borderRadius:"30px" }); //外框
$(".container>div").css({ margin: "1rem auto", overflow: "auto" }); //每一行
$("span:not(:last-child)").addClass("each-title"); //标题
$("li:first-of-type").addClass("each-item-hover"); //选项块 “全部”
//移入选项块(先取消全部背景,然后加上背景orange),移除选项块(如果选项卡都没有被选中,就恢复“全部”选项卡的初始class)
$("li").addClass("each-item").hover(function () {
$(this).addClass("each-item-hover").siblings().removeClass("each-item-hover");
}, function () {
$(this).removeClass("each-item-hover");
//-------------------attr()方法的回调函数-----------------------
var hasChosen = 0; //第三方变量,判断一行中的选项卡是否有被选中的,不能在attr()方法的回到函数中定义,否则每次遍历都会重新声明
$(this).parent().children("li").attr("data-chosen", function (i, origValue) {
origValue === "chosen" ? hasChosen = 1 : null;
});
!hasChosen ? $(this).parent().children("li:first-of-type").addClass("each-item-hover") : null;
//----------------------------------------------------
}).on("click", function (e) {
//点击选项块,把除自身之外的兄弟元素的自定属性取消(取消选中标记)
$(this).siblings().css({ backgroundColor: "", color: "" }).removeAttr("data-chosen");
//如果点击的是选项块不是“全部”,就设置自定义属性(添加选中标记)
if( e.target.innerText !== "全部" ){
$(this).css({ backgroundColor: "orange", color: "white" }).attr("data-chosen", "chosen");
} //else none
//将选中的选项块所属行的父元素 class 设置到选中的选项块的自定义属性上
$(this).attr("data-parent",`${$(this).parent().prop("class")}`);
//获取每一行选中的项目,将其添加到筛选结果栏
var getChosenItemToResult = (chosenParentSelector, attribute)=>{
$(".result-detail").find(`[data-parent='${attribute}']`).remove();
if (e.target.innerText !== "全部") {
var newBrandBlock = $(this).clone().css({ width: "12%", margin: "auto 0.1rem" }).append("<span> ×</span>").on("click", function () {
$(this).remove();
$(`.${chosenParentSelector}`).children().css({ backgroundColor: "", color: "" });
$(`.${chosenParentSelector}`).children(":first").css({ backgroundColor: "orange", color: "white" });
});
$(".result-detail").append(newBrandBlock);
} //else none
}
getChosenItemToResult($(this).parent().prop("class"), $(this).parent().attr("class")); //直接调函函数导致this指向window,因此可以使用箭头函数指向父级而解决问题
});
//筛选结果显示值
var unChosenText = $(".result-detail-initial").text();
var unChosenClassName = "result-detail-initial";
$("html").on("click", function () {
//jQuery 颜色使用rgb作为返回值
var brandFirstBack = $(".brand").find("li:first").css("background-color");
var sizeFirstBack = $(".size").find("li:first").css("background-color");
var colorFirstBack = $(".color").find("li:first").css("background-color");
if (brandFirstBack === "rgb(255, 165, 0)" && brandFirstBack === sizeFirstBack && sizeFirstBack === colorFirstBack) {
!$(".result-detail").children().hasClass("result-detail-initial") ? $(".result-detail").append(`<span class="${unChosenClassName}">${unChosenText}</span>`) : null;
} else {
$(".result-detail-initial").remove();
}
})
}
})
</script>
</html>
购物车功能
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<style>
*{margin:0;padding:0;}
body{background: #eeeeee}
input[type="checkbox"]{appearance:none;width:0.8rem;height:0.8rem;background-color:white;margin:0 0.5rem;text-align:center;line-height:1rem;vertical-align:middle}
input[type="checkbox"]:hover{background-color:#AF8875;}
input[type="checkbox"]:checked{border:1px solid #FDF7FF;background-color:#FDF7FF}
input[type="checkbox"]:checked:after{content:"✓";color:purple;font-weight:bolder;font-size:0.8rem;}
.container{width:80%;height:100%;overflow:auto;margin:auto;}
.container::-webkit-scrollbar{width:3px;height:8px;background:#A73B00;}
.container::-webkit-scrollbar-thumb{background:#F9F871;}
.title{width:100%;height:4rem;display:inline-table;position:sticky;top:0;overflow:hidden;background:#69bff8;font-size:0.8rem;}
.title span{display:table-cell;vertical-align:middle;text-align:center}
.title .title-chose{width:10%;text-align:start}
.title-info{width:20%;}
.product-info{width:15%;padding:0 2.5%}
.title-describe{width:20%}
.product-describe{width:18%;padding:0 2%}
.title-price,.product-price,.title-count,.product-count,.title-price-count,.product-price-count,.title-remove,.product-remove{width:11%;font-size:0.8rem}
.store-title{width:100%;height:2rem;background:#C9F987}
.store-title label,.store-title a{height:100%;display:inline-block;font:bolder 0.8rem/2rem 宋体;}
.store-title a{text-decoration:none; color:#892000;}
.product-detail{padding-top:0.5rem;font-size:0;}
.product-detail li{height:15%;list-style-type:none;display:inline-block;vertical-align:middle;font-size:0.8rem;}
.product-img{width:10%;}
.product-img img{width:100%;height:100%;}
.product-price,.product-count,.product-price-count,.product-remove{text-align:center;}
.product-count input{vertical-align:top;}
.product-count input[type="button"]{appearance:none;width:2rem;height:1.5rem;border:0;background:#61DBE1;color:black;}
.product-count input[type="button"]:hover{cursor:pointer}
.product-count input[type="button"]:active{background:#F9F871;border:1px solid #F9F871;color:white;}
.product-count input[type="number"]{outline:none;width:3rem;height:1.5rem;text-align:center;border:0}
.product-count input[type="number"]::-webkit-inner-spin-button,.product-count input[type="number"]::-webkit-outer-spin-button{appearance:none;}
.product-price-count{color:red}
.product-remove:hover{color:red;cursor:pointer}
.total{width:80%;height:3rem;position:absolute;bottom:0;background:white;overflow:auto;text-align:right;}
.total div,.total button{height:100%;border:0;float:left;color:white;font:bolder 1.2rem 宋体;}
.total div{width:78%;background:#BFC1FF;line-height:3rem;padding-right:2%}
.total button{width:20%;border:0;background:#898CC9;}
</style>
</head>
<body>
<div class="container">
<section class="title">
<span class="title-chose"><input id="chose-all"type="checkbox"/><label for="chose-all">全选</label></span>
<span class="title-info">商品信息</span>
<span class="title-describe">商品参数</span>
<span class="title-price">单价</span>
<span class="title-count">数量</span>
<span class="title-price-count">金额</span>
<span class="title-remove">操作</span>
</section>
<section class="cart">
<div class="store-title">
<input id="stores" class="store-check" type="checkbox"/><label for="stores" class="store-name">店铺:</label>
<a href="#">null</a>
</div>
<ul class="product-detail">
<li class="product-check"><input type="checkbox"/></li>
<li class="product-img"><img src="" alt="商品图片"></li>
<li class="product-info"><span></span></li>
<li class="product-describe">规格:<span></span><br>尺寸:<span></span></li>
<li class="product-price">$<span></span></li>
<li class="product-count"><input type="button" value="-"/><input type="number" value="1"/><input type="button" value="+"/></li>
<li class="product-price-count">$<span></span></li>
<li class="product-remove"><span>移除商品</span></li>
<div style="clear:both;"></div>
</ul>
</section>
<section class="total">
<div>总计:<span></span></div>
<button>结算</button>
</section>
</div>
</body>
<script>
//suit for mobile device
$("html").css("font-size",`${$("html").innerWidth / 375 * 12}px`);
//render data to page
function renderData(resultData){
//link Elements
var cart = $(".cart").attr("data-index","0");
//add new element shop
for(let j = resultData.length - 1; j >= 0 ; j--){
j != 0 ? cart.after(cart.clone().attr("data-index",`${j}`)) : null;
// for(let i = resultData[j].products.length; i > 0; i--) {
// //mistake: (---below---)
// //if there isn't slice() to locate the productDetail , it will add more than expected numbers
// // i != 0 ? productDetail.slice(resultData[j].products.length).after(productDetail.clone()).attr("data",mk) : null;
// }
}
//add new element products in terms of added shop elements
var productDetail = $(".product-detail");
for(let j = resultData.length - 1; j >= 0 ; j--){
for(let i = resultData[j].products.length - 1; i >= 0; i--) {
i != 0 ? productDetail.eq(j).after(productDetail.eq(j).clone()) : null;
}
}
//link Elements again after added elements
var cart = $(".cart");
var productDetail = $(".product-detail");
var titleCheck = $(".title-chose input");
var shopCheck = $(".store-check");
var shopCheckLabel = $(".store-check~label");
var shopName = $(".store-title a");
var eachCheck = $(".product-check input");
var img = $(".product-img img");
var info = $(".product-info span");
var describeSpecs = $(".product-describe span:first-of-type");
var describeSize = $(".product-describe span:last-of-type");
var price = $(".product-price span");
var decrease = $(".product-count").children("[type='button']:even");
var increase = $(".product-count").children("[type='button']:odd");
var counts = $(".product-count").children("[type='number']");
var countsPrice = $(".product-price-count span");
var productRemove = $(".product-remove");
var totalPrice = $(".total span");
//get data from ajax and set data-index attribute for event
let m = 0; //index of elements
for(let j = 0; j < resultData.length; j++){
shopName.eq(j).text(resultData[j].store); //get shop name
shopCheck.eq(j).attr({"data-index":`${j}`,"id":`${j}`});
shopCheckLabel.eq(j).attr("for",`${j}`);
for(let i = 0; i < resultData[j].products.length; i++){
if( m < productDetail.length ){ //in terms of the productDetail elemnts' numbers
//get data
img.eq(m).attr("src",resultData[j].products[i].url); //get productImg
info.eq(m).text(resultData[j].products[i].name); //get product information
describeSpecs.eq(m).text(resultData[j].products[i]["describe-specs"]);
describeSize.eq(m).text(resultData[j].products[i]["describe-size"]); //get product describe
price.eq(m).text(resultData[j].products[i].price); //get count price
counts.eq(m).val(resultData[j].products[i].counts);
countsPrice.eq(m).text((parseFloat(counts.eq(m).val() * parseFloat(price.eq(m).text()))).toFixed(2));
console.log(parseFloat(price.eq(m).text()) )
//set index
eachCheck.eq(m).attr("data-index",`${j}-${i}`); //set check index
price.eq(m).attr("data-index",`${j}-${i}`); //set price index
decrease.eq(m).attr("data-index",`${j}-${i}`);
increase.eq(m).attr("data-index",`${j}-${i}`); //set - + input index
counts.eq(m).attr("data-index",`${j}-${i}`); //set count index
countsPrice.eq(m).attr("data-index",`${j}-${i}`); //set counts' summary price
productRemove.eq(m).attr("data-index",`${j}-${i}`); //set remove operator index
productDetail.eq(m).attr("data-index",`${j}-${i}`); //set each productDetail index
m++;
} // else none
}
}
function countTotalPrice(){
let countsPriceTotal = 0;
let countsPrice = $(".product-price-count span");
for(let i = 0; i < countsPrice.length; i++){
countsPriceTotal += parseFloat(countsPrice.eq(i).text());
}
totalPrice.text(countsPriceTotal.toFixed(2));
};
countTotalPrice();
return {titleCheck,shopCheck,eachCheck,img,info,describeSpecs,describeSize,price,decrease,increase,counts,countsPrice,productRemove,productDetail,cart,countTotalPrice};
}
//check products
function checkProducts(titleCheck, shopCheck, eachCheck){
function toggleAll(){
for(let j = 0; j < shopCheck.length; j++){
if( !shopCheck.eq(j).prop("checked") ) {
titleCheck.prop("checked",false);
break; //avoid continuous circle that leads to cover the value
} else if(shopCheck.eq(j).prop("checked")) {
titleCheck.prop("checked",true);
}
}
}
eachCheck.on("click",function(){
var curLineIndex = $(this).attr("data-index").substring(0,1);
var curEachChecks = eachCheck.filter(`[data-index^='${curLineIndex}']`);
var curLineShop = shopCheck.filter(`[data-index='${curLineIndex}']`);
for(let i = 0; i < curEachChecks.length; i++) {
if ( !curEachChecks.eq(i).prop("checked") ) {
curLineShop.prop("checked",false);
toggleAll();
break; //avoid continuous circle that leads to cover the value
} else {
curLineShop.prop("checked",true);
toggleAll();
}
}
});
shopCheck.on("click",function(){
var curLineIndex = $(this).attr("data-index");
var curEachChecks = eachCheck.filter(`[data-index^='${curLineIndex}']`);
for( let i = 0; i < curEachChecks.length; i++ ) {
if( $(this).prop("checked") ) {
curEachChecks.eq(i).prop("checked",true);
} else {
curEachChecks.eq(i).prop("checked",false);
}
}
toggleAll();
});
titleCheck.on("click",function(){
if( $(this).prop("checked") ) {
eachCheck.prop("checked",true);
shopCheck.prop("checked",true);
} else {
eachCheck.prop("checked",false);
shopCheck.prop("checked",false);
};
});
}
//summary price
function changeNum(price,decrease,increase,counts,countsPrice,productDetail,countTotalPrice){
decrease.on("click",function(){
for(let i = 0; i < counts.length; i++ ){
if($(this).attr("data-index") === counts.slice(i).attr("data-index")){
var curCount = counts.filter(`[data-index='${counts.slice(i).attr("data-index")}']`);
var afterCount = parseInt(curCount.val()) - 1;
var curPrice = price.filter(`[data-index='${price.slice(i).attr("data-index")}']`);
var curCountsPrice = countsPrice.filter(`[data-index='${countsPrice.slice(i).attr("data-index")}']`);
if(parseInt(afterCount) !== 0){
//decrease the input’s number
curCount.val(afterCount);
curCountsPrice.text((parseFloat(curPrice.text()) * afterCount).toFixed(2));
} else {
curCountsPrice.text((parseFloat(curPrice.text()) * parseInt(curCount.val(1).val())).toFixed(2));
}
} //else none
}
});
increase.on("click",function(){
for(let i = 0; i < counts.length; i++){
if($(this).attr("data-index") === counts.slice(i).attr("data-index")){
var curCount = counts.filter(`[data-index='${counts.slice(i).attr("data-index")}']`);
var afterCount = parseInt(curCount.val()) + 1;
var curPrice = price.filter(`[data-index='${price.slice(i).attr("data-index")}']`);
var curCountsPrice = countsPrice.filter(`[data-index='${countsPrice.slice(i).attr("data-index")}']`);
//increase the input’s number
curCount.val(afterCount);
curCountsPrice.text((parseFloat(curPrice.text()) * afterCount).toFixed(2));
} //else none
}
});
counts.on("blur",function(){
for(let i = 0; i < price.length; i++){
if($(this).attr("data-index") === price.slice(i).attr("data-index")){
var curCount = counts.filter(`[data-index='${counts.slice(i).attr("data-index")}']`)
var curPrice = price.filter(`[data-index='${price.slice(i).attr("data-index")}']`);
var curCountsPrice = countsPrice.filter(`[data-index='${countsPrice.slice(i).attr("data-index")}']`);
if(parseInt(curCount.val()) <= 0 || isNaN(parseInt(curCount.val()))){
curCountsPrice.text(parseInt(curCount.val(1).val()) * parseFloat(curPrice.text()));
} else {
curCount.val(parseInt(curCount.val())); //change producr numbers directly from the input,ensure the value is integer
curCountsPrice.text(parseInt(curCount.val()) * parseFloat(curPrice.text()));
}
}
}
});
productDetail.on("click",function(){
countTotalPrice();
})
}
//operate remove each line product
function eachRemove(productRemove,productDetail,cart,totalPrice){
productRemove.on("click",function(){
productDetail.filter(`[data-index='${$(this).attr("data-index")}']`).remove();
cart.filter(":not(:has(.product-detail))").remove();
let countsPriceTotal = 0;
let afterRemovePriceCount = $(".product-price-count span");
for(let i = 0; i < afterRemovePriceCount.length; i++){
countsPriceTotal += parseFloat(afterRemovePriceCount.eq(i).text());
}
$(".total span").text(countsPriceTotal.toFixed(2));
})
}
//ajax function
$.ajax({
url:"http://localhost:3000/shoppingcart",
methos:"get",
data:{},
dataType:"json",
success:function(result,status){
let render = renderData(result);
changeNum(render.price,render.decrease,render.increase,render.counts,render.countsPrice,render.productDetail,render.countTotalPrice)
checkProducts(render.titleCheck, render.shopCheck,render.eachCheck);
eachRemove(render.productRemove,render.productDetail,render.cart,render.totalPrice);
},
error:function(xhr,status,error){
console.log(status);
console.log(error);
}
});
</script>
</html>
{
"shoppingcart": [
{
"id": 0,
"store": "小米旗舰店",
"products": [
{
"id": 0,
"name": "官方提供在线图片压缩软件实现,实现一键压缩图片大小,专业的高质量图片压缩工具",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "默认",
"describe-size": "106*1*3(cm)",
"price": "153.99",
"counts": 2
},
{
"id": 1,
"name": "JPG压缩、PNG压缩、BMP压缩功能,为用户解决压缩图片的问题",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "PNG",
"describe-size": "126*16*3(cm)",
"price": "1.09",
"counts": 5
},
{
"id": 2,
"name": "软件实现,实现一键压缩图片大小,专业的高质量图片",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "JPG",
"describe-size": "16*16*3(cm)",
"price": "1523.99",
"counts": 5
}
]
},
{
"id": 0,
"store": "JU旗舰店",
"products": [
{
"id": 0,
"name": "一键压缩图片大小,专业的高质量图,现一键压缩图片大小,专业的高质量图",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "BMP",
"describe-size": "196*16*3(cm)",
"price": "153.99",
"counts": 2
},
{
"id": 1,
"name": "一键压缩图片大小,专业的高质量图,现一键压缩图片大小,专业的高质量图",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "默认",
"describe-size": "126*16*3(cm)",
"price": "153.99",
"counts": 5
},
{
"id": 2,
"name": "PNG压缩、BMP压缩功能,为用户解决压缩图片的问题",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "JAP",
"describe-size": "16*16*3(cm)",
"price": "153.99",
"counts": 3
},
{
"id": 3,
"name": "PNG压缩、BMP压缩功能,为用户解决压缩图片的问题",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "POP",
"describe-size": "16*16*3(cm)",
"price": "153.99",
"counts": 5
}
]
},
{
"id": 0,
"store": "opsu旗舰店",
"products": [
{
"id": 0,
"name": "add the chosen item highlight style and remove all the default and the other items' highlight style",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "默认",
"describe-size": "56*16*3(cm)",
"price": "1.99",
"counts": 1
},
{
"id": 1,
"name": "官方提供在线图片压缩软件实现,实现一键压缩图片大小",
"url": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fc%2F54c9d6178cad7_130_170.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1671891151&t=858820e9b62f3e58d72e26713dc92012",
"describe-specs": "默认",
"describe-size": "16*16*3(cm)",
"price": "153.99",
"counts": 1
}
]
}
]
}
暂无评论内容