JS21 – JQuery – 手风琴效果 关键词菜单选项卡 购物车页面


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)
  • 说明
    1. css() 方法:样式都添加在行内属性;具有隐式迭代功能。例如,选中多个元素,会自动给每个设置好样式
    2. css() 方法:不能直接设置部分伪类伪元素样式,可通过 $(选择器).append("<style>选择器::after{display:none}</style>"); 方式间接实现
    3. 操作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 的值

布局.png

$("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>

jQuery 示例 - 手风琴效果.gif

关键词菜单选项卡 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": "银灰"}
  ]
}

菜单关键词选项卡.gif

关键词菜单选项卡 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>

菜单关键词选项卡2.gif

购物车功能

<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

        }
      ]
    }
  ]
}

购物车页面.gif

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容