产品文档
商城排序的产品需求文档(PRD ProductionRequestDescription)是由产品经理产出的描述应用功能的;我们的排期,技术方案都要根据这个文档产出
- 做一个华为手机的电商页面
- 页面中的数据是动态获取的(如有新手机发布,页面上要自动展示新手机)
- 点击商家时间、价格、热度、销量可以按照相应的维度排序
- 第一次点击按钮升序排序,再次点击该按钮降序排序
- 点击某个维度后,如价格,再次点击该维度是降序,如果第一次点击的是价格,第二次点击销量按照销量升序排列
html
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>商城排序DEMO</title><!-- IMPORT CSS --><link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css"><link rel="stylesheet" href="css/index.css"></head><body><!-- BT 中建议所有内容都存放在 CONTAINER 容器中 --><div class="container"><!-- NAV导航 --><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="javascript:;">商城排序</a><div class="collapse navbar-collapse"><ul class="navbar-nav"><!-- DATA-PAI记录的是每个按钮应该按照哪个维度进行排序 --><li class="nav-item" data-pai="data-time"><a class="nav-link" href="javascript:;">上架时间</a></li><li class="nav-item" data-pai="data-price"><a class="nav-link" href="javascript:;">价格</a></li><li class="nav-item" data-pai="data-hot"><a class="nav-link" href="javascript:;">热度</a></li></ul></div></nav><!-- CARD-LIST商品列表 --><div class="card-deck"><!-- <div class="card"><img class="card-img-top" src="img/1.jpg" alt=""><div class="card-body"><h6 class="card-title">HUAWEI Mate 10 4GB+64GB 全网通版(亮黑色)</h6><p class="card-text">价格:¥5000</p><p class="card-text">好评:100000</p><p class="card-text"><small class="text-muted">上架时间:2019-08-07</small></p></div></div> --></div></div><!-- IMPORT JS --><script src="js/index.js"></script></body></html>
js
~ function () {let _DATA = null;//第一步:从服务器获取数据(AJAX),然后绑定在页面中// 1. 基于 AJAX 获取服务器端数据,把数据存储到 DATA 中let xhr = new XMLHttpRequest;// 创建 AJAX 的实例xhr.open('GET', 'json/product.json', false);// 打开一个请求的链接,基于 GET 请求和同步编程完成xhr.onreadystatechange = function () {if (xhr.status === 200 && xhr.readyState === 4)// 监听服务器返回的状态信息(在 HTTP 状态码为200,请求状态为4的时候能拿到数据{_DATA = xhr.responseText;// 基于 responseText 获取响应回来的信息(JSON 字符串)}};xhr.send();// 发送 AJAX 请求_DATA = JSON.parse(_DATA); //=>_DATA:获取的都是 JSON 字符串,我们要让其变为对象// 第二步:把获取的数据绑定在页面中// 根据获取的 DATA:DATA 当中有多少项,我就动态创建出多少个 card 盒子(项目中都是基于字符串拼接的方式,把需要创建的 card 拼出来let htmlStr = ``;_DATA.forEach(item => {// ITEM 是每一项(对象),包含需要展示的每一个产品的详细信息:我们需要拿出每一项信息来展示到页面中(拼到模板字符串中)let {title, price, time, hot, img} = item;// 基于解构赋值获取信息htmlStr += `<div class="card"data-price="${price}"data-time="${time}"data-hot="${hot}"><img class="card-img-top" src="${img}" alt=""><div class="card-body"><h6 class="card-title">${title}</h6><p class="card-text">价格:¥${price}</p><p class="card-text">好评:${hot}</p><p class="card-text"><small class="text-muted">上架时间:${time}</small></p></div></div>`;});// 把需要的数据绑定在元素 card 的自定义属性 data-xxx 上(后期需要这些数据,直接基于自定义属性获取即可)let cardDeck = document.querySelector('.card-deck');cardDeck.innerHTML = htmlStr;// 把拼接好的 card 字符串,放到页面指定容器中(card-deck)// 第三步:点击实现升降序排序let navList = document.querySelectorAll('.navbar-nav li'),cardList = cardDeck.querySelectorAll('.card');// 循环给所有的按钮绑定点击事件,点击的时候按照指定的规则排序for (let i = 0; i < navList.length; i++) {let item = navList[i];item['data-type'] = -1; // 控制升降序item.onclick = function () {// 点击当前的某个按钮,让其按照升降序切换,而其余的都应该回归原始-1[].forEach.call(navList, item => (item === this ? this['data-type'] *= -1 :item['data-type'] = -1));cardList = [].slice.call(cardList, 0);cardList.sort((next, cur) => {// 获取当前按钮记录的排序方式 data-time / data-price / data-hotlet pai = this.getAttribute('data-pai');cur = cur.getAttribute(pai);next = next.getAttribute(pai);if (pai === "data-time") {// 获取的是日期数据:我们要把字符串中的 “-” 给去掉cur = cur.replace(/-/g, '');next = next.replace(/-/g, '');}return (next - cur) * this['data-type'];});cardList.forEach(item => cardDeck.appendChild(item));}}/*// 给价格按钮绑定点击事件// 给按钮设置一个自定义属性 DATA-TYPE 存储排序方式:-1降序 1升序navList[1]['data-type'] = -1;navList[1].onclick = function () {// 控制升降序切换this['data-type'] *= -1;// 把元素集合转换为数组,让其按照价格进行排序cardList = Array.prototype.slice.call(cardList, 0);cardList.sort((next, cur) => {// 绑定数据的时候,把产品价格信息设置为元素的自定义属性,需要的时候获取cur = cur.getAttribute('data-price');next = next.getAttribute('data-price');return (next - cur) * this['data-type'];});// 循环数组中的每一项,让其按照最新的顺序依次添加到页面中,完成页面排序cardList.forEach(item => cardDeck.appendChild(item));}navList[2]['data-type'] = -1;navList[2].onclick = function () {// 控制升降序切换this['data-type'] *= -1;// 把元素集合转换为数组,让其按照价格进行排序cardList = Array.prototype.slice.call(cardList, 0);cardList.sort((next, cur) => {// 绑定数据的时候,把产品价格信息设置为元素的自定义属性,需要的时候获取cur = cur.getAttribute('data-hot');next = next.getAttribute('data-hot');return (next - cur) * this['data-type'];});// 循环数组中的每一项,让其按照最新的顺序依次添加到页面中,完成页面排序cardList.forEach(item => cardDeck.appendChild(item));} */// 使用jQuery格式实现商城排序// 通过单例模式来管理商城排序的代码let shopModule = (function ($) {// 想要操作谁就先获取谁(项目中尽可能把创建变量提前并放在一起)let $navList = $('.navbar-nav li'), // $()是创建这个类的实例$cardBox = $('.card-deck'),$cardList = null,_DATA = null;// 从服务器获取数据function queryData () {// 基于JQ中的ajax方法获取数据$.ajax ({url:'json/product.json',method:'GET',async:false,success:result => {// 从服务器获取数据成功会执行success,result存储的就是获取到的数据,并且默认就已经转换为 json 格式的对象_DATA = result;}});}// 把数据绑定在页面中function bindHTML () {if (!_DATA) return;let HTML = ``;$.each(_DATA,(index, item) => {let {title, img, price, hot, time} = item;HTML += `<div class="card" time = "${time}" prict = "${price}" hot = "${hot}"><img class="card-img-top" src="${img}" alt=""><div class="card-body"><h6 class="card-title">${title})</h6><p class="card-text">${price}</p><p class="card-text">${hot}</p><p class="card-text"><small class="text-muted">${time}</small></p></div>`;});$cardBox.html(HTML);// 获取所有的card$cardList = $cardBox.children('.card');}// 实现商城排序function sortHandle () {$navList.attr('typeA', -1);$navList.on(click, function () {// this:当前点击的li(原生js对象)通过$(this)变成JQ对象let $this = $(this),pai = $this.attr('pai'); // time / price / hot$this.attr('typeA', $this.attr('typeA') * -1).siblings().attr('typeA',-1);$cardList.sort((A, B) => {let $A = $(A),$B = $(B);$A = $A.attr(pai);$B = $B.attr(pai);pai === "time" ? ($A = $A.replace(/-/g,""), $B = $B.replace(/-/g,"")) : null;return ($A - $B) * $this.attr('typeA');});$cardList.each((index, item) => $cardBox.append(item));});}return {// 在单例模式当中引用命令模式// 当前模块的入口:想让商城排序开始执行,我们只需要执行init,在init中会按照顺序依次完成具体// 的业务逻辑init () { // 相当于 init:function () {}queryData();bindHTML();sortHandle();}}})(jQuery); // 传一个 jQuery 然后形参写 $,保证闭包里永远不受别的类库影响shopModule.init();}();
