视图渲染的大致思想

# 视图渲染的大致思想 ## 数据渲染 ![image.png](https://cos.easydoc.net/13568421/files/ll96zhim.png) ![image.png](https://cos.easydoc.net/13568421/files/ll975okw.png) ![image.png](https://cos.easydoc.net/13568421/files/ll977c18.png) ![image.png](https://cos.easydoc.net/13568421/files/ll97gojl.png) ## 动态跳转 ### 1. keyword跳转 ```javascript function searchByKeyword() { searchProducts("keyword", $("#keyword_input", false).val()); function searchProducts(name, value, forced) { // 下面那个方法是动态添加参数的, 第一个参数是老地址, 第二个是key, 第三个是value, 第四个是是否强制添加同名key location.href = replaceParamVal(location.href,name,value,forced) } } ``` ### 2. 品牌的跳转 注意: 品牌可以多选 ```thymeleaf <a th:href="${'javascript:searchProducts(&quot;brandId&quot;,'+brand.brandId+', true)'}"> ``` ### 3. 分类的跳转 注意: 分类不能多选 ```thymeleaf <a th:href="${'javascript:searchProducts(&quot;catalog3Id&quot;,'+catalog.catalogId+', false)'}" th:text="${catalog.catalogName}"> </a> ``` ### 4. 规格参数的跳转 注意: 分类可以多选 ```thymeleaf <a th:href="${'javascript:searchProducts(&quot;attrs&quot;,&quot;'+attr.attrId+'_'+attrValue+'&quot;, true)'}" th:text="${attrValue}"> </a> ``` 调用思路大体不差, 都是基于原来的路径上拼接参数, 一种是强制添加参数, 一种是参数覆盖 ### 5. 分页的跳转与渲染 如果不能正确比较并显示样式, 一般是integer类型的数据没有变成string ![image.png](https://cos.easydoc.net/13568421/files/ll98jkve.png) ```JavaScript $(".page_a").click(function () { var pn = $(this).attr("pn"); if (pn == null) { pn = $(this).prev().prev().val() // 完善指定跳转功能 } var href = location.href; if (href.indexOf("pageNum") != -1) { //替换pageNum location.href = replaceParamVal(href, "pageNum", pn); } else { location.href = location.href + "&pageNum=" + pn; } return false; }) ``` **调用逻辑: 判断是否有分页参数, 如果没有则添加, 有则覆盖替换, 不改变其他参数** ### 6. 排序功能 ```JavaScript $(".sort_a").click(function () { // changeStyle(this); $(this).toggleClass("desc"); let sort = $(this).attr("sort"); sort = $(this).hasClass("desc") ? sort + "_desc" : sort + "_asc"; location.href = replaceParamVal(location.href, "sort", sort,false); return false; }); ``` 整体的思路: 因为是价格排序, 因此key已经确定了, 但是value可能是asc或者desc, 我们想要实现点一下升序, 再点一下降序, 我们可以使用toggleClass该方法, 该方法可以动态添加class, 若有则删除, 若无则添加, 然后通过判断是否有该class来决定是asc或desc, 最后动态添加条件即可, 不可强制添加 > 注意, 把那个方法干掉, 因为这个渲染没有任何的意义, CV上述代码 ![image.png](https://cos.easydoc.net/13568421/files/ll99pmyq.png) ### 7. 价格区间 ```JavaScript $("#skuPriceSearchBtn").click(function () { let from = $(`#skuPriceFrom`).val(); let to = $(`#skuPriceTo`).val(); if ("" == from && "" == to) return // 如果没有值, 不能找范围 let query = from + "_" + to; location.href = replaceParamVal(location.href, "skuPrice", query,false); }); ``` ![image.png](https://cos.easydoc.net/13568421/files/ll9a6lz7.png) ### 8. 查看是否有库存 ```JavaScript $("#showHasStock").change(function () { if ($(this).prop("checked")) { location.href = replaceParamVal(location.href, "hasStock", 1, false); } else { let re = eval('/(hasStock=)([^&]*)/gi'); location.href = (location.href + "").replace(re, ""); } return false; }); ``` ![image.png](https://cos.easydoc.net/13568421/files/ll9agfab.png) ### 9. 动态展示插叙条件 ```thymeleaf <div class="JD_pre" th:each="attr : ${result.attrs}" th:if="${param.attrs != null ? !#lists.contains(param.attrs, attr.attrId+'_'+attr.attrValue) : true}"> ``` > 这里我首先判断了是否有这个条件, 如果有这个条件就继续判断这个条件是否是当前规格参数, 如果是就不显示, 如果没有或不是就显示 **** ```thymeleaf <div class="JD_pre" th:if="${param.catalog3Id == null}"> ``` > 参数有分类就不显示 **** ```tymeleaf <div class="JD_nav_wrap" th:if="${param.brandId == null}"> ``` > 参数有品牌就不显示 ### 10. 面包屑功能 ```html <a th:if="${nav.navName != '分类'}" th:href="${'list.html?'+nav.link}" th:each="nav:${result.navs}"><span th:text="${nav.navName}"></span>:<span th:text="${nav.navValue}"></span> x</a> <a th:if="${nav.navName == '分类'}" th:each="nav:${result.navs}"><span th:text="${nav.navName}"></span>:<span th:text="${nav.navValue}"></span></a> ``` 这里对分类来了个特殊处理, 分类的面包屑不能干掉 #### 前端页面的封装 ```java private WebVO getWebVO(EsSearchParamVO esSearchParamVO, Integer pageNum, Integer totalPage, RespAggToObject result) { // 封装页面数据(渲染页面的方法, 若进行前后端分离, 该方法可以直接删除), 分页信息一定存在 List<String> pageNavs = new ArrayList<String>() { { int cur = pageNum - 2; while (this.size() != 5 && cur <= totalPage) { // 如果还没有6个或没有遍历完 if (cur < 1) { cur++; }else { this.add(cur+""); cur++; } } } }; List<Nav> navs = new ArrayList<>(); // 初始化面包屑集合, 避免控制很 List<String> attrs = esSearchParamVO.getAttrs(); // 获取所有的规格参数查询条件 Long catalog3Id = esSearchParamVO.getCatalog3Id(); List<Long> brandIds = esSearchParamVO.getBrandId(); if (attrs != null && !attrs.isEmpty()) { // 存在规格参数查询条件时 navs.addAll( attrs.stream().map(attr -> { Nav nav = new Nav(); String[] navBody = attr.split("_"); String navValue = navBody[1]; Long attrId = Long.valueOf(navBody[0]); String navName = result.attrs.stream().filter(attrVO -> attrVO.getAttrId().equals(attrId)) .collect(Collectors.toList()).get(0).getAttrName(); // 不可能查询条件只有一个规格参数, 进来一定会有keyword或catalogId String oldStr = "&attrs=" + attrId + "_" + navValue; // 这里需要改一下前端 String link = esSearchParamVO.getSearchParam().replace(oldStr, ""); return nav.setNavName(navName).setNavValue(navValue).setLink(link); }).collect(Collectors.toList()) ); } // 规格参数的面包屑 if (catalog3Id != null) { // 存在分类 String navValue = result.catalogs.stream().filter(catalogVO -> catalogVO.getCatalogId().equals(catalog3Id)) .collect(Collectors.toList()).get(0).getCatalogName(); // 面包屑的值就是分类的名字 String navName = "分类"; // 面包屑的名字是分类 String oldStr = "catalog3Id=" + catalog3Id; String link = esSearchParamVO.getSearchParam().replace(oldStr, ""); link = link.replace("&&", "&"); // 处理不是分类开头的情况 navs.add(new Nav().setNavName(navName).setNavValue(navValue).setLink(link)); } // 分类的面包屑 if (brandIds != null && !brandIds.isEmpty()) { navs.addAll( brandIds.stream().map(brandId -> { String navValue = result.brands.stream().filter(brandVO -> brandVO.getBrandId().equals(brandId)).collect(Collectors.toList()) .get(0).getBrandName(); String navName = "品牌"; String oldStr = "&brandId=" + brandId; String link = esSearchParamVO.getSearchParam().replace(oldStr, ""); return new Nav().setNavName(navName).setNavValue(navValue).setLink(link); }).collect(Collectors.toList()) ); } return new WebVO(pageNavs, navs); } private static class WebVO { public final List<String> pageNavs; public final List<Nav> navs; public WebVO(List<String> pageNavs, List<Nav> navs) { this.pageNavs = pageNavs; this.navs = navs; } } ``` ##### 亮点说明 1. 获取规格参数 > 老师的获取规格参数有一个非常致命的问题, 即调用微服务去获取, 微服务调用存在一个响应时间, 如果数据量足够大, 这会使得整体吞吐量下滑, 非常的糟糕, 因此, 不建议采取该方式 > 而对应的数据其实在响应结果中, 即聚合里面的数据, 因为你通过这个条件查出来的, 聚合一定有这个规格条件, 因此一定可以获取对应的名字, 这样吞吐量大大提高 2. 编码与解码 > 编码: 即将字符串或其他音频文件转换为0101的二进制, 相当于将抽象的东西编码成数字 > 解码: 即将二进制数字还原其抽象的状态, 如字符串等 ```java // 进一步封装页面请求参数字段 String queryString = servletRequest.getQueryString(); // 编码后的查询条件 // 对查询条件进行解码, 避免浏览器的URL编码和后端编码不一致问题, 直接从解码解决所有的问题 queryString = URLUtil.decode(queryString); esSearchParamVO.setSearchParam(queryString); ``` > 这里获取参数的时候, 这个参数已被编码, 因此我们需要解码, 为什么不在后端对字符串编码呢? 原因是编码的逻辑不一样, 导致后端整体逻辑出现问题!