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