产品文档

商城排序的产品需求文档(PRD ProductionRequestDescription)是由产品经理产出的描述应用功能的;我们的排期,技术方案都要根据这个文档产出

  1. 做一个华为手机的电商页面
  2. 页面中的数据是动态获取的(如有新手机发布,页面上要自动展示新手机)
  3. 点击商家时间、价格、热度、销量可以按照相应的维度排序
  4. 第一次点击按钮升序排序,再次点击该按钮降序排序
  5. 点击某个维度后,如价格,再次点击该维度是降序,如果第一次点击的是价格,第二次点击销量按照销量升序排列

html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>商城排序DEMO</title>
  6. <!-- IMPORT CSS -->
  7. <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
  8. <link rel="stylesheet" href="css/index.css">
  9. </head>
  10. <body>
  11. <!-- BT 中建议所有内容都存放在 CONTAINER 容器中 -->
  12. <div class="container">
  13. <!-- NAV导航 -->
  14. <nav class="navbar navbar-expand-lg navbar-light bg-light">
  15. <a class="navbar-brand" href="javascript:;">商城排序</a>
  16. <div class="collapse navbar-collapse">
  17. <ul class="navbar-nav">
  18. <!-- DATA-PAI记录的是每个按钮应该按照哪个维度进行排序 -->
  19. <li class="nav-item" data-pai="data-time">
  20. <a class="nav-link" href="javascript:;">上架时间</a>
  21. </li>
  22. <li class="nav-item" data-pai="data-price">
  23. <a class="nav-link" href="javascript:;">价格</a>
  24. </li>
  25. <li class="nav-item" data-pai="data-hot">
  26. <a class="nav-link" href="javascript:;">热度</a>
  27. </li>
  28. </ul>
  29. </div>
  30. </nav>
  31. <!-- CARD-LIST商品列表 -->
  32. <div class="card-deck">
  33. <!-- <div class="card">
  34. <img class="card-img-top" src="img/1.jpg" alt="">
  35. <div class="card-body">
  36. <h6 class="card-title">HUAWEI Mate 10 4GB+64GB 全网通版(亮黑色)</h6>
  37. <p class="card-text">价格:¥5000</p>
  38. <p class="card-text">好评:100000</p>
  39. <p class="card-text"><small class="text-muted">上架时间:2019-08-07</small></p>
  40. </div>
  41. </div> -->
  42. </div>
  43. </div>
  44. <!-- IMPORT JS -->
  45. <script src="js/index.js"></script>
  46. </body>
  47. </html>

js

  1. ~ function () {
  2. let _DATA = null;
  3. //第一步:从服务器获取数据(AJAX),然后绑定在页面中
  4. // 1. 基于 AJAX 获取服务器端数据,把数据存储到 DATA 中
  5. let xhr = new XMLHttpRequest;
  6. // 创建 AJAX 的实例
  7. xhr.open('GET', 'json/product.json', false);
  8. // 打开一个请求的链接,基于 GET 请求和同步编程完成
  9. xhr.onreadystatechange = function () {
  10. if (xhr.status === 200 && xhr.readyState === 4)
  11. // 监听服务器返回的状态信息(在 HTTP 状态码为200,请求状态为4的时候能拿到数据
  12. {
  13. _DATA = xhr.responseText;
  14. // 基于 responseText 获取响应回来的信息(JSON 字符串)
  15. }
  16. };
  17. xhr.send();
  18. // 发送 AJAX 请求
  19. _DATA = JSON.parse(_DATA); //=>_DATA:获取的都是 JSON 字符串,我们要让其变为对象
  20. // 第二步:把获取的数据绑定在页面中
  21. // 根据获取的 DATA:DATA 当中有多少项,我就动态创建出多少个 card 盒子(项目中都是基于字符串拼接的方式,把需要创建的 card 拼出来
  22. let htmlStr = ``;
  23. _DATA.forEach(item => {
  24. // ITEM 是每一项(对象),包含需要展示的每一个产品的详细信息:我们需要拿出每一项信息来展示到页面中(拼到模板字符串中)
  25. let {title, price, time, hot, img} = item;
  26. // 基于解构赋值获取信息
  27. htmlStr += `<div class="card"
  28. data-price="${price}"
  29. data-time="${time}"
  30. data-hot="${hot}">
  31. <img class="card-img-top" src="${img}" alt="">
  32. <div class="card-body">
  33. <h6 class="card-title">${title}</h6>
  34. <p class="card-text">价格:¥${price}</p>
  35. <p class="card-text">好评:${hot}</p>
  36. <p class="card-text"><small class="text-muted">上架时间:${time}</small></p>
  37. </div>
  38. </div>`;
  39. });
  40. // 把需要的数据绑定在元素 card 的自定义属性 data-xxx 上(后期需要这些数据,直接基于自定义属性获取即可)
  41. let cardDeck = document.querySelector('.card-deck');
  42. cardDeck.innerHTML = htmlStr;
  43. // 把拼接好的 card 字符串,放到页面指定容器中(card-deck)
  44. // 第三步:点击实现升降序排序
  45. let navList = document.querySelectorAll('.navbar-nav li'),
  46. cardList = cardDeck.querySelectorAll('.card');
  47. // 循环给所有的按钮绑定点击事件,点击的时候按照指定的规则排序
  48. for (let i = 0; i < navList.length; i++) {
  49. let item = navList[i];
  50. item['data-type'] = -1; // 控制升降序
  51. item.onclick = function () {
  52. // 点击当前的某个按钮,让其按照升降序切换,而其余的都应该回归原始-1
  53. [].forEach.call(navList, item => (item === this ? this['data-type'] *= -1 :
  54. item['data-type'] = -1));
  55. cardList = [].slice.call(cardList, 0);
  56. cardList.sort((next, cur) => {
  57. // 获取当前按钮记录的排序方式 data-time / data-price / data-hot
  58. let pai = this.getAttribute('data-pai');
  59. cur = cur.getAttribute(pai);
  60. next = next.getAttribute(pai);
  61. if (pai === "data-time") {
  62. // 获取的是日期数据:我们要把字符串中的 “-” 给去掉
  63. cur = cur.replace(/-/g, '');
  64. next = next.replace(/-/g, '');
  65. }
  66. return (next - cur) * this['data-type'];
  67. });
  68. cardList.forEach(item => cardDeck.appendChild(item));
  69. }
  70. }
  71. /*
  72. // 给价格按钮绑定点击事件
  73. // 给按钮设置一个自定义属性 DATA-TYPE 存储排序方式:-1降序 1升序
  74. navList[1]['data-type'] = -1;
  75. navList[1].onclick = function () {
  76. // 控制升降序切换
  77. this['data-type'] *= -1;
  78. // 把元素集合转换为数组,让其按照价格进行排序
  79. cardList = Array.prototype.slice.call(cardList, 0);
  80. cardList.sort((next, cur) => {
  81. // 绑定数据的时候,把产品价格信息设置为元素的自定义属性,需要的时候获取
  82. cur = cur.getAttribute('data-price');
  83. next = next.getAttribute('data-price');
  84. return (next - cur) * this['data-type'];
  85. });
  86. // 循环数组中的每一项,让其按照最新的顺序依次添加到页面中,完成页面排序
  87. cardList.forEach(item => cardDeck.appendChild(item));
  88. }
  89. navList[2]['data-type'] = -1;
  90. navList[2].onclick = function () {
  91. // 控制升降序切换
  92. this['data-type'] *= -1;
  93. // 把元素集合转换为数组,让其按照价格进行排序
  94. cardList = Array.prototype.slice.call(cardList, 0);
  95. cardList.sort((next, cur) => {
  96. // 绑定数据的时候,把产品价格信息设置为元素的自定义属性,需要的时候获取
  97. cur = cur.getAttribute('data-hot');
  98. next = next.getAttribute('data-hot');
  99. return (next - cur) * this['data-type'];
  100. });
  101. // 循环数组中的每一项,让其按照最新的顺序依次添加到页面中,完成页面排序
  102. cardList.forEach(item => cardDeck.appendChild(item));
  103. } */
  104. // 使用jQuery格式实现商城排序
  105. // 通过单例模式来管理商城排序的代码
  106. let shopModule = (function ($) {
  107. // 想要操作谁就先获取谁(项目中尽可能把创建变量提前并放在一起)
  108. let $navList = $('.navbar-nav li'), // $()是创建这个类的实例
  109. $cardBox = $('.card-deck'),
  110. $cardList = null,
  111. _DATA = null;
  112. // 从服务器获取数据
  113. function queryData () {
  114. // 基于JQ中的ajax方法获取数据
  115. $.ajax ({
  116. url:'json/product.json',
  117. method:'GET',
  118. async:false,
  119. success:result => {
  120. // 从服务器获取数据成功会执行success,result存储的就是获取到的数据,并且默认就已经
  121. 转换为 json 格式的对象
  122. _DATA = result;
  123. }
  124. });
  125. }
  126. // 把数据绑定在页面中
  127. function bindHTML () {
  128. if (!_DATA) return;
  129. let HTML = ``;
  130. $.each(_DATA,(index, item) => {
  131. let {title, img, price, hot, time} = item;
  132. HTML += `<div class="card" time = "${time}" prict = "${price}" hot = "${hot}">
  133. <img class="card-img-top" src="${img}" alt="">
  134. <div class="card-body">
  135. <h6 class="card-title">${title})</h6>
  136. <p class="card-text">${price}</p>
  137. <p class="card-text">${hot}</p>
  138. <p class="card-text">
  139. <small class="text-muted">${time}</small></p>
  140. </div>`;
  141. });
  142. $cardBox.html(HTML);
  143. // 获取所有的card
  144. $cardList = $cardBox.children('.card');
  145. }
  146. // 实现商城排序
  147. function sortHandle () {
  148. $navList.attr('typeA', -1);
  149. $navList.on(click, function () {
  150. // this:当前点击的li(原生js对象)通过$(this)变成JQ对象
  151. let $this = $(this),
  152. pai = $this.attr('pai'); // time / price / hot
  153. $this.attr('typeA', $this.attr('typeA') * -1).siblings().attr('typeA',-1);
  154. $cardList.sort((A, B) => {
  155. let $A = $(A),
  156. $B = $(B);
  157. $A = $A.attr(pai);
  158. $B = $B.attr(pai);
  159. pai === "time" ? ($A = $A.replace(/-/g,""), $B = $B.replace(/-/g,"")) : null;
  160. return ($A - $B) * $this.attr('typeA');
  161. });
  162. $cardList.each((index, item) => $cardBox.append(item));
  163. });
  164. }
  165. return {
  166. // 在单例模式当中引用命令模式
  167. // 当前模块的入口:想让商城排序开始执行,我们只需要执行init,在init中会按照顺序依次完成具体
  168. // 的业务逻辑
  169. init () { // 相当于 init:function () {}
  170. queryData();
  171. bindHTML();
  172. sortHandle();
  173. }
  174. }
  175. })(jQuery); // 传一个 jQuery 然后形参写 $,保证闭包里永远不受别的类库影响
  176. shopModule.init();
  177. }();