1.构建详情页
步骤0:确定访问路径
步骤二:复制 ~/static/goods.html 内容,导入第三方资源(css、js)
head: { title: '列表页面', link: [ {rel:'stylesheet',href: '/style/goods.css'}, {rel:'stylesheet',href: '/style/common.css'}, {rel:'stylesheet',href: '/style/bottomnav.css'}, {rel:'stylesheet',href: '/style/jqzoom.css'}, ], script: [ { type: 'text/javascript', src: '/js/header.js' }, { type: 'text/javascript', src: '/js/goods.js' }, { type: 'text/javascript', src: '/js/jqzoom-core.js' }, ] },
步骤三:导入公共资源
<script> import TopNav from '@/components/TopNav' import HeaderSearch from '@/components/HeaderSearch' import BottomNav from '@/components/BottomNav' import Footer from '@/components/Footer' export default { components: { TopNav, HeaderSearch, BottomNav, Footer, }, } </script>
步骤四:添加原页面js特效
2.详情
2.1分析
2.2接口
GET http://localhost:10010/web-service/sku/goods/2600242
返回值
{ skuid:"商品ID,skuid", spuid:"商品ID,skuid", goods_name:"商品名称", price:"价格", on_sale_date:"上架时间", comment_count:"评论数量", comment_level:"评论级别(1-5)", cat1_info:{ id:"分类ID", cat_name:"分类名称" }, cat2_info:{ id:"分类ID", cat_name:"分类名称" }, cat3_info:{ id:"分类ID", cat_name:"分类名称" }, logo:{ smlogo:"小LOGO(50x50)", biglogo:"大LOGO(350x350)", xbiglogo:"超大LOGO(800x800)" }, photos:[ { smimg:"商品图片(50x50)", bigimg:"商品图片(350x350)", xbigimg:"商品图片(800x800)" }, ... ], description:"商品描述", aftersale:"售后", stock:"库存量", spec_list:[ { id:"规格ID", spec_name:"规格名称", options:[ { id:"选项ID", option_name:"选项名称" } ... ] } ... ], spec_info:{ id_list:"规格ID:选项ID|规格ID:选项ID|...", id_txt:"规格名称:规格选项|规格名称:规格选项|..." }, sku_list:[ { skuid:"SKUID", id_list:"规格ID:选项ID|规格ID:选项ID|..." }, ... ] }
2.3初始化数据
insert into tb_sku_photo(sku_id,url) values(2600242,'http://img12.360buyimg.com/n1/s450x450_jfs/t1/100605/24/7603/222062/5dfc6d30Ec375bf0a/e29b6690731acb24.jpg'); insert into tb_sku_photo(sku_id,url) values(2600242,'http://img12.360buyimg.com/n1/s450x450_jfs/t1/110371/2/1323/189888/5dfc6d30E073c3495/cb256ec2d3cf9ae2.jpg'); insert into tb_sku_photo(sku_id,url) values(2600242,'http://img12.360buyimg.com/n1/s450x450_jfs/t1/95005/38/7465/139593/5dfc6d2fEd2317126/63b5253237353618.jpg');
2.4后端实现:JavaBean
SkuPhoto : sku对应的所有图片
OneSkuResult:用于封装sku详情
步骤一:创建SkuPhoto,根据tb_sku_photo表编写内容
package com.czxy.changgou4.pojo; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; /** * Created by liangtong. */ @TableName("tb_sku_photo") @Data public class SkuPhoto { @TableId(type = IdType.AUTO) private Integer id; //外键 @TableField(value="sku_id") @JsonProperty("sku_id") private Integer skuId; @TableField(exist = false) private Sku sku; @TableField(value="url") private String url; }
步骤二:创建OneSkuResult,根据接口返回结果编写内容
package com.czxy.changgou4.vo; import com.czxy.changgou4.pojo.Category; import com.czxy.changgou4.pojo.Specification; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.Date; import java.util.List; import java.util.Map; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Data public class OneSkuResult { private Integer skuid; private Integer spuid; @JsonProperty("goods_name") private String goodsName; private Double price; @JsonProperty("on_sale_date") private Date onSaleDate; @JsonProperty("comment_count") private Integer commentCount; @JsonProperty("comment_level") private Integer commentLevel; @JsonProperty("cat1_info") private Category cat1Info; @JsonProperty("cat2_info") private Category cat2Info; @JsonProperty("cat3_info") private Category cat3Info; private Map<String, String> logo; private List<Map> photos; private String description; private String aftersale; private Integer stock; @JsonProperty("spec_list") private List<Specification> specList; // id_list:'规格ID:选项ID|规格ID:选项ID|...', // id_txt:'规格名称:选项名称|规格名称:选项名称|...' @JsonProperty("spec_info") private Map<String, String> specInfo; @JsonProperty("sku_list") private List<Map<String, String>> skuList; }
2.5后端实现:Mapper
步骤一:修改skuCommentMapper,完成“评论级别”功能
/** * 通过spu查询评论打分(星星)的平均数 * @param spuId * @return */ @Select("SELECT AVG(star) FROM tb_sku_comment WHERE spu_id = #{spuId}") public Integer findAvgStarBySpuId(@Param("spuId") Integer spuId);
步骤二:创建SkuPhotoMapper,完成“通过skuId查询对应的所有的图片”功能
package com.czxy.changgou4.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.czxy.changgou4.pojo.SkuPhoto; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import java.util.List; /** * Created by liangtong. */ @Mapper public interface SkuPhotoMapper extends BaseMapper<SkuPhoto> { /** * 通过skuId查询对应的所有的图片 * @param spuId * @return */ @Select("select * from tb_sku_photo where sku_id = #{spuId}") @Results({ @Result(property="id", column="id"), @Result(property="skuId", column="sku_id"), @Result(property="url", column="url") }) public List<SkuPhoto> findSkuPhotoBySkuId(Integer spuId); }
步骤三:修改SkuMapper,添加“查询指定spuId的所有sku”功能
/** * 查询指定spuId的所有sku * @param spuId * @return */ @Select("select * from tb_sku where spu_id = #{spuId}") @ResultMap("skuResult") public List<Sku> findSkuBySpuId(Integer spuId);
2.6后端实现
步骤一:修改SkuService,添加findSkuById 方法
/** * 查询详情 * @param skuid * @return */ public OneSkuResult findSkuById(Integer skuid);
步骤二:修改SkuServiceImpl,完成“查询详情”功能
package com.czxy.changgou4.service.impl; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.czxy.changgou4.mapper.*; import com.czxy.changgou4.pojo.Sku; import com.czxy.changgou4.pojo.SkuPhoto; import com.czxy.changgou4.pojo.Specification; import com.czxy.changgou4.pojo.Spu; import com.czxy.changgou4.service.SkuService; import com.czxy.changgou4.vo.ESData; import com.czxy.changgou4.vo.OneSkuResult; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Service @Transactional public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements SkuService { @Resource private SkuCommentMapper skuCommentMapper; @Resource private SpuMapper spuMapper; @Resource private CategoryMapper categoryMapper; @Resource private SkuPhotoMapper skuPhotoMapper; @Resource private SpecificationMapper specificationMapper; @Override public List<ESData> findESData() { //1 查询所有详情sku List<Sku> skulist = baseMapper.findAllSkus(); //2 将SKU 转换成 ESData List<ESData> esDataList = new ArrayList<>(); for (Sku sku:skulist){ ESData esData = new ESData(); // id esData.setId(sku.getId()); // 图片地址 esData.setLogo(sku.getSpu().getLogo()); // 商品名称 esData.setSkuName(sku.getSkuName()); // all “华为xx {"机身颜色":"白色","内存":"3GB","机身存储":"16GB"} 荣耀 ” esData.setAll(sku.getSkuName()+" " + sku.getSpecInfoIdTxt() + " " +sku.getSpu().getBrand().getBrandName()); // on_sale_time esData.setOnSaleTime(sku.getSpu().getOnSaleTime()); // brand_id esData.setBrandId(sku.getSpu().getBrandId()); // cat_id esData.setCatId(sku.getSpu().getCat3Id()); // Map<String, Object> specs;// 可搜索的规格参数,key是参数名,值是参数值 Map<String,Object> specs = JSON.parseObject(sku.getSpecInfoIdTxt(), Map.class); // Map newSpecs = new HashMap(); // for(String key : specs.keySet()){ // newSpecs.put("spec" + key , specs.get(key)); // } esData.setSpecs(specs); // price 价格 esData.setPrice(sku.getPrice()); // spu_name esData.setSpuName(sku.getSpu().getSpuName()); // stock 库存 esData.setStock(sku.getStock()); // description esData.setDescription(sku.getSpu().getDescription()); // packages;//规格与包装 esData.setPackages(sku.getSpu().getPackages()); // aftersale;//售后保障 esData.setAftersale(sku.getSpu().getAftersale()); // midlogo; esData.setMidlogo(sku.getSpu().getLogo()); // comment_count; 评价数 Integer comment_count = skuCommentMapper.findNumBySpuId(sku.getSpu().getId()); esData.setCommentCount(comment_count); //销售量 esData.setSellerCount(10); esDataList.add(esData); } return esDataList; } @Override public OneSkuResult findSkuById(Integer skuid) { OneSkuResult skuResult = new OneSkuResult(); // 1 查找sku基本信息 Sku sku = baseMapper.selectById(skuid); // 2 根据sku查找spu信息 Spu spu = spuMapper.findSpuById(sku.getSpuId()); // 3 赋值 // skuid; skuResult.setSkuid(sku.getId()); // spuid; skuResult.setSpuid(sku.getSpuId()); // 商品名称 skuResult.setGoodsName(sku.getSkuName()); // 价格 skuResult.setPrice(sku.getPrice()); // 上架时间 skuResult.setOnSaleDate(spu.getOnSaleTime()); // 评价数 Integer comment_count = skuCommentMapper.findNumBySpuId(spu.getId()); skuResult.setCommentCount(comment_count); // 评论级别 skuResult.setCommentLevel(skuCommentMapper.findAvgStarBySkuId(sku.getId())); // 一级分类 skuResult.setCat1Info(categoryMapper.selectById(spu.getCat1Id())); // 二级分类 skuResult.setCat2Info(categoryMapper.selectById(spu.getCat2Id())); // 三级分类 skuResult.setCat3Info(categoryMapper.selectById(spu.getCat3Id())); // 第一张图片 Map<String,String> logo = new HashMap(); logo.put("smlogo",spu.getLogo()); logo.put("biglogo",spu.getLogo()); logo.put("xbiglogo",spu.getLogo()); skuResult.setLogo(logo); // 通过skuId查询对应的所有的图片 List<SkuPhoto> skuPhotoList = skuPhotoMapper.findSkuPhotoBySkuId(sku.getId()); List<Map> photos = new ArrayList<>(); for(SkuPhoto sp:skuPhotoList){ Map<String,String> map = new HashMap(); map.put("smimg",sp.getUrl()); map.put("bigimg",sp.getUrl()); map.put("xbigimg",sp.getUrl()); photos.add(map); } skuResult.setPhotos(photos); // 商品描述 skuResult.setDescription(spu.getDescription()); // 售后 skuResult.setAftersale(spu.getAftersale()); // 库存量 skuResult.setStock(sku.getStock()); // List<SpecResult> spec_list; 根据分类查找规格和规格选项 List<Specification> spec_list = specificationMapper.findSpecificationByCategoryId(spu.getCat3Id()); skuResult.setSpecList(spec_list); // //id_list:'规格ID:选项ID|规格ID:选项ID|...', // //id_txt:'规格名称:选项名称|规格名称:选项名称|...' // Map<String, String> spec_info; Map<String,String> spec_info = new HashMap<>(); spec_info.put("id_list",sku.getSpecInfoIdList()); spec_info.put("id_txt",sku.getSpecInfoIdTxt()); skuResult.setSpecInfo(spec_info); // List<Map<String, String>> sku_list; List<Sku> skuBySpuIdList = baseMapper.findSkuBySpuId(spu.getId()); List<Map<String, String>> sku_list = new ArrayList<>(); for(Sku s : skuBySpuIdList){ Map<String,String> map = new HashMap<>(); map.put("skuid",s.getId().toString()); map.put("id_list",s.getSpecInfoIdList()); sku_list.add(map); } skuResult.setSkuList(sku_list); // 返回结果 return skuResult; } }
/** * 查询详情 * @param skuid * @return */ @GetMapping("/goods/{skuid}") public BaseResult<OneSkuResult> findSkuById(@PathVariable("skuid") Integer skuid){ OneSkuResult sku = skuService.findSkuById(skuid); return BaseResult.ok("查询成功", sku); }
2.7前端实现
详情页面需要进行SSR
步骤一:修改 “apiserver.js”,查询详情
步骤二:修改 Goods.vue 页面,使用asyncData进行查询
步骤三:修改 Goods.vue 页面,显示当前位置
步骤四:修改 Goods.vue 页面,处理放大镜图片
步骤五:修改 Goods.vue 页面,商品详情
编写specOptionSelect方法
methods: { specOptionSelect(spec,option) { // 拼接标记符,规格id:选项id let flag = spec.id + ':' + option.id // 判断id_list中是否有‘标记符’,如果没有返回-1 return this.goodsInfo.spec_info.id_list.indexOf(flag) != -1 } },
步骤六:修复bug,图片大小的原因,导致“放大镜”中等图太大,遮盖小图
问题图示
解决
1. <style> 2. .midpic img { 3. width: 100%; 4. } 5. </style>
3.规格操作
点击“规格”时,切换SKU的id
步骤一:修改 Goods.vue 页面,给每一个规格选项绑定点击事件
步骤二:修改 Goods.vue 页面,完成 selectSpec 函数