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

1,646 阅读22分钟

jQuery 是什么

  • jQuery 本质:是一个快速,轻量级且功能丰富的 JavaScript 方法库,不是常说的前端框架,前端框架一般来说主要还是 VUE、React、Angular。
  • jQuery 优点:选择器、隐式迭代、链式编程、解决兼容(jquery1功能,jquery3已经废弃),从而简化了HTML文档的 遍历、事件、动画和Ajax交互,从而实现了快速的Web开发
  • jQuery 特色:一行代码,少写多做
  • jQuery 官网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 的所有后代

遍历同级

index()

  • 功能:返回指定元素相对于其他指定元素的 index 位置,如果未找到元素,index() 将返回 -1。
  • 语法:$(*selector*).index(element)

slice()

  • 功能:slice() 方法选取基于索引的元素的子集,参数 start(必需),规定开始选取元素的位置,索引号从 0 开始,如果是负数,从末端开始选,stop(可选),结束位置,如果省略,则末端结束,索引号从 0 开始,如果是负数,从末端开始。
  • 语法:$(*selector*).slice(*start,stop*)

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] -> 从选择器倒数第二个开始,往上/往前,直到给定选择器条件的最前面一个

$("li").click(function(){ console.log($(this).index()) });  //获取当前点击的下标
console.log($(".hot").index($("#favorite")));   //获取class为hot的元素中id为favorite的下标

$("p").slice().css("background-color","yellow");  //标黄所有 <p> 元素
$("p").slice(2).css("background-color","yellow");  //标黄索引 2 以及后面的 <p> 元素
$("p").slice(2,4).css("background-color","yellow");  //标黄索引 2 到索引 4 的 <p> 元素

过滤遍历

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

$("li").html();  //list
$("li").text();  //listlistlistlistlist
$("input").val();//content

//设置
$("#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);  // 切换一个或多个类

$("li").eq(1).addClass("before").siblings().removeClass("after");    //指定修改 li 元素中第二个的class样式
$("li").removeClass("before").eq(2).addClass("after");               //指定修改 li 元素中第三个的class样式

操作尺寸 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 的值
    • 即使设置了 display:none;,依然能获取到

布局.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();
$("li").offset();            //{top: 8, left: 48}
$("li").eq(1).offset();      //{top: 29, left: 48}

//设置偏移坐标:$(*selector*).offset({top:*value*,left:*value*})
$(".relative .absolute").offset();   //{top: 329, left: 208}
$(".relative .absolute").offset({left:50,top:50});
$(".relative .absolute").offset();   //{top: 50, left: 50}
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 效果方法

闪现动画 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() 方法已完成!"); 
});

渐隐动画 fadeOut() fadeIn() fadeToggle() fadeTo()

  • 功能:fadeOut() - 淡出;fadeIn() - 淡入;fadeToggle() - 切换;fadeTo() - 指定渐变;底层以 display:none/block;opacity:[number]; 实现
  • 语法$(*selector*).fadeToggle(*speed,timing-function,callback*); $(*selector*).fadeTo(speed,opacity,timing-function,callback);
  • 参数:fadeTo() 没有默认参数,必须加上 slow/fast/Time
  • 可选参数 speed:隐藏/显示的速度,可以三类值:slow、fast、毫秒
  • 可选参数 opacity:fadeTo() 方法,表示给定的不透明度(值介于 0 与 1 之间)
  • 可选参数 timing-function:运动曲线
  • 可选参数 callback:隐藏或显示完成后所执行的函数,如果调用callback时,在函数名后直接加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行,而且只会 执行一次,只有当作回调参数的时候才会有多个元素而 执行多次
<div style="background-color:black;width:300px;height:300px;display:none;"></div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
    $("div").fadeIn("slow","linear",function(){console.log("fadeIn 执行结束")});    //fadeIn 执行结束
    $("div").fadeOut("slow","linear",function(){console.log("fadeOut 执行结束")});  //fadeOut 执行结束
    $("div").fadeToggle("slow","linear",function(){console.log("fadeToggle 执行结束")});    //fadeToggle 执行结束
    $("div").fadeTo("slow",0.5,"linear",function(){console.log("fadeTo 方法的四个参数:执行速度、透明度、运动曲线、执行完毕后调用的回调函数")});
</script>

jQuery 渐隐动画.gif

折叠动画 slideDown() slideUp() slideToggle()

  • 功能:slideDown() - 下滑;slideUp() - 上滑;slideToggle() - 切换;底层以 display:none/block;opacity:[number]; 实现
  • 语法$(*selector*).slideToggle(*speed,timing-function,callback*);
  • 可选参数 speed:隐藏/显示的速度,可以三类值:slow、fast、毫秒
  • 可选参数 timing-function:运动曲线
  • 可选参数 callback:隐藏或显示完成后所执行的函数,如果调用callback时,在函数名后直接加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行,而且只会 执行一次,只有当作回调参数的时候才会有多个元素而 执行多次
$("button").click(function () {
    $("div").slideToggle(function () {
        console.log("animate 动画结束")
    });
});

jQuery 折叠动画.gif

综合动画 - animate()

  • 功能:创建自定义动画
  • 语法$(*selector*).animate({params},speed,timing-function,callback);
  • 必需的 params 参数:定义形成动画的 CSS 属性
  • 可选的 speed 参数:规定效果的时长,取值:"slow"、"fast" 或毫秒
  • 可选的 timing-function 参数:运动曲线
  • 可选的 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");
<button>animate</button>
<div style="background-color:black;width:100px;height:100px;"></div>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
    $("button").click(function () {
        $("div").animate({
            width: "200px",
            height: "200px",
            "background-color": "pink",  //颜色无效
            transform: "rotate(45deg)",  //transform 无效
            display: "block"
        }, 1000, "linear", function () {
            console.log("animate 动画结束")
        });
    });
</script>

animate动画.gif

停止动画 - stop() finish()

  • 功能:停止动画
  • 语法$(*selector*).stop(stopAll,goToEnd);
  • 可选 stopAll 参数:规定是否应该清除动画队列。默认是 false(仅停止活动的动画,允许任何排入队列的动画向后执行)
  • 可选 goToEnd 参数:规定是否立即完成当前动画。默认是 false(不立即完成)
  • finish() 方法停止当前运行的动画,移除所有排队的动画,并为被选元素完成所有动画。该方法与 .stop(true,true) 方法类似,不同的是,finish() 也会引起所有排队动画的 CSS 属性停止。
$("#panel").stop();            //动画中途暂停,还可以继续执行
$("#panel").stop(true);        //队列中的动画都清除,动画中途结束,不可继续执行
$("#panel").stop(false,true);  //当前动画立即完成,后续队列不清除,还可继续执行

//stop() 停止动画 -> 可用于模拟防抖
ele.stop().toggle();

jQuery 事件方法

ready() on() off() one() $(this)

  • 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);
});

hover()

  • 语法:元素集合.hover(移入时触发的函数, 移出时触发的函数),如果只传一个函数,会在移入移出的时候都触发,该函数,是jQuery里面一个特殊的事件
$("div").hover(
    function(){ console.log("function1") },
    function(){ console.log("function2") }
)

trigger() triggerHandler()

  • 功能:trigger() 方法触发被选元素上指定的事件以及事件的默认行为(比如表单提交)
  • 区别
    • trigger() 方法与 triggerHandler() 不同的是,trigger() 不触发事件的默认行为
    • trigger() 会操作 jQuery 对象匹配的所有元素,而 triggerHandler() 只影响第一个匹配元素。
    • 由 triggerHandler() 创建的事件不会在 DOM 树中冒泡,如果目标元素不直接处理它们,则不会发生任何事情。
//通过代码的形式自动触发事件
//在 1s 后触发点击事件
$("li").on("click", function(){
    console.log("click li");
})
setTimeout(() => {
    $("li").trigger("click");
}, 1000);

trigger 方法.gif

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); 
});

jQuery jsonp 请求

//jsonp 仅适用于get请求,因此method可以省略不写
$.ajax({
    url:"http://www.runoob.com/try/ajax/jsonp.php",
    dataType:"jsonp",
    jsonp:"jsoncallback",
    jsonpCallback:"test"
})
function test(obj){
    console.log(obj);   //(2) ['customername1', 'customername2']
}

//jsonp在jQuery中不必声明回调函数,jQuery会自动创建一个回调函数
$.ajax({
    url:"http://www.runoob.com/try/ajax/jsonp.php",
    dataType:"jsonp",
    jsonp:"jsoncallback",
    // jsonpCallback:"test"
})

//并且jQuery会将回调函数处理的结果通过success方法输出,或者可以通过调用then方法得到
//success 和 then 方法都可获取,因此二者取其一即可
$.ajax({
    url:"http://www.runoob.com/try/ajax/jsonp.php",
    dataType:"jsonp",
    jsonp:"jsoncallback",
    // jsonpCallback:"test"
    success(obj){
        console.log(obj);   //(2) ['customername1', 'customername2']
    }
}).then(res=>{
    console.log(res);   //(2) ['customername1', 'customername2']
})

image.png

image.png

jQuery 钩子函数

window 钩子和 jQuery 钩子

  • 含义:在计算机编程中,钩子函数主要用于通过拦截在软件组件之间传递的函数调用或消息或事件来改变或增强操作系统,应用程序或其他软件组件的行为。处理这种截获的函数调用,事件或消息的代码称为钩子,它的本质就是用以处理系统消息的程序,通过系统调用,把它挂入系统。钩子函数可用于许多目的,包括调试和扩展功能。常见的钩子函数:react的生命周期函数、vue的生命周期函数等,即可以捕捉您自己进程或其它进程发生的事件。
  • Ajax 钩子函数:在ajax执行请求的过程中,随之触发的函数,能够通过这个函数明确知道ajax处理请求的哪一阶段,这类函数一般置于全局范围内。
//window 钩子:onload -> 所有外部资源(图片、JavaScript、css、DOM)加载完成后执行
window.onload = function(){
    console.log("window 钩子", function(){
        console.log("该回调函数会在window钩子执行完之后再执行");
    })
}

//jQuery 钩子:ready -> 所有的DOM节点加载完成后执行的钩子函数
$(window).ready(function(){
    console.log("jQuery钩子",""初始化任务);
});
//jQuery 钩子简化
$(function(){
    console.log("jQuery钩子",""初始化任务);
});

ajaxStart()

  • ajaxStart 功能:当前页面作用域,第一个Ajax发送之前执行
$(window).ajaxStart(function(){
    console.log("当前页面作用域,第一个Ajax发送之前执行");
    console.log("显示loading");
    $("#loading").css("display","block");
});

ajaxSend() ajaxSuccess() ajaxError() ajaxComplete()

  • ajaxSend 功能:每一个Ajax发送之前执行
  • ajaxSuccess 功能:每一个Ajax成功都会触发一次
  • ajaxError 功能:每一个Ajax失败后都会触发一次
  • ajaxComplete 功能:每一个Ajax执行完成后都会触发一次,不论成功还是失败
$(window).ajaxSend(function(){
    console.log("每一个Ajax发送之前执行");
    console.log("显示loading");
});
$(window).ajaxSuccess(function(){
    console.log("每一个Ajax成功都会触发一次");
    console.log("隐藏loading...(如果只有一个ajax请求)");
});
$(window).ajaxError(function(){
    console.log("每一个Ajax失败后都会触发一次");
});
$(window).ajaxComplete(function(){
    console.log("每一个Ajax执行完成后都会触发一次,不论成功还是失败");
})

ajaxStop() 

  • 功能:ajaxStop() 方法规定所有的 AJAX 请求完成时运行的函数。当 AJAX 请求完成时,jQuery 会检查是否存在更多的 AJAX 请求。如果没有其他请求正在等待运行,ajaxStop()方法会运行指定的函数。
  • 注意: 自 jQuery 版本 1.8 起,该方法只被附加到文档。
$(document).ajaxStop(function(){ 
        console.log("所有 AJAX 请求已完成,当前页面作用域的最后一个Ajax成功");
        console.log("隐藏loading");
        $("#loading").css("display","none");
    }
);`

when()

  • 功能:利用 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){
        // 后续操作
      }  
    }) ;
}

jQuery 扩展方法

extend() extend(true)

  • 功能jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。
  • 语法:$.extend( [deep ], target, object1, ..., objectN )
  • 参数说明:
    • deep:可选,Boolean类型 指示是否深度合并对象,默认为false,如果该值为true,且多个对象的某个同名属性也都是对象,则该"属性对象"的属性也将进行合并。
    • target:Object类型,目标对象,其他对象的成员属性将被附加到该对象上。
    • object1:可选,Object类型,第一个被合并的对象。
    • objectN:可选,Object类型,第N个被合并的对象。
//jQuery的浅拷贝和深拷贝 -> 原理:在原有对象的基础上扩展内容,因此能够实现拷贝的效果,由于该功能不会扩展一个undefined的功能,也就不会拷贝undefined了
//说明:
//    1. 如果第一个参数为true,表示深拷贝;
//    2. 从第二个参数(或第三个参数)开始,都属于原对象,将要拷贝给第一个参数(或第二个参数)

//浅拷贝
$.extend(objCopy,objOri,{other:"other thing"})
//深拷贝
$.extend(true,objCopy,objOri,{other:"other thing"})

自定义扩展插件 - 选项卡

  • 应用自定义jQuery插件的一般要求:(1)DOM结构符合插件要求;(2)引入CSS样式;(3)引入JavaScript文件并初始化
<!-- 引入 -->
<link rel="stylesheet" href="./test.css">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script src="./test.js"></script>

<!-- DOM要求 -->
<div id="container">
    <ul class="option">
        <li class="active">1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <ul class="content">
        <li class="active">1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
</div>

<!-- 初始化 -->
<script type="text/javascript">
    onload = function(){
        $("#container").tabs(2);
    }
</script>
.option,.content{
    list-style:none;
    border:1px solid black;
    padding:0;
    margin:0;
    text-align:center;
    font:normal bolder 2rem/5rem Aria;
}
.option{
    display:flex;
    height:10%;
}
.option li {
    flex:auto;
}
.content li{
    height:20%;
    display:none;
}
.content .active{
    display:block;
}
.option .active,.option li:hover,.option-checked,.content-checked{
    background-color:black;
    color:red;
}
$.fn.extend({
    tabs(index) {
        var options = $(this).find(".option li");
        var contents = $(this).find(".content li");
        options.eq(index).addClass("active").siblings().removeClass("active");
        contents.eq(index).addClass("active").siblings().removeClass("active");
        options.on("click", function () {
            $(this).addClass("active").siblings().removeClass("active");
            var index = $(this).index();
            contents.eq(index).addClass("active").siblings().removeClass("active");
        })
    }
});

自定义jQuery插件 - 选项卡.gif

jQuery 插件库 - Owl Carousel

Owl Carousel has been choosen as number one jQuery plugin by hundreds of developers. Now its time for a new version that comes with lots of new features and even more user friendly API. owlcarousel2.github.io/OwlCarousel…

示例

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