Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十五(实现商品页面搜索功能,以及分页功能)(1)

  • (2)处理返回的数据

    在这里插入图片描述

    el: “#searchApp”,

    data: {

    search:{},

    goodsList:[],

    total: 0,

    totalPage: 0,

    selectedSku:{}

    },

    created(){//这是个构造方法

    //获取请求参数

    const search = ly.parse( location.search.substring(1));

    this.search = search;

    //发送后台数据

    this.loadData();

    },

    methods:{

    loadData(){

    //发送数据到后台

    ly.http.post(“/search/page”,this.search).then(resp => {

    //保存分页结果

    this.total = resp.data.total;

    this.totalPage = resp.data.totalPage;

    //保存当前页商品数据

    resp.data.items.forEach(goods =>{

    // 把JSON处理为JS对象

    goods.skus = JSON.parse(goods.skus);//JSON.parse将JSON字符串转换为JSON对象

    //初始化被选中的sku

    goods.selectedSku = goods.skus[0];

    })

    this.goodsList = resp.data.items;

    }).catch(error =>{

    })

    }

    },

    (3)完善HTML代码

    在这里插入图片描述

    • ¥

      促{{ goods.subTitle }}

      已有2000人评价

      加入购物车

      对比

      关注

      刷新页面

      显示成功

      在这里插入图片描述

      (4)处理上述的代码
      1)设置价格

      定义ly变量

      在这里插入图片描述

      设置价格格式

      在这里插入图片描述

      刷新页面

      在这里插入图片描述

      2)处理字太多下不下

      在这里插入图片描述

      促{{ goods.subTitle.substring(0,15) }}…

      刷新页面

      在这里插入图片描述

      3)设置点击小图片切换大图片

      在这里插入图片描述

      在这里插入图片描述

      • 刷新页面

        在这里插入图片描述

        设置鼠标动到图片上切换选择并显示对应的图片

        在这里插入图片描述

        鼠标悬浮直接切换当前的sku,之后图片价格和描述都会改变

        @mouseenter=“goods.selectedSku=sku”

        切换成功

        在这里插入图片描述

        2、设置分页条

        在这里插入图片描述

        在这里插入图片描述

      • 设置初始页

        在这里插入图片描述

        search.page = parseInt(search.page) || 1;

        刷新页面。我们可以看到设置了page的初始值为1

        在这里插入图片描述

        设置是否选中当前页

        在这里插入图片描述

      • 刷新页面

        在这里插入图片描述

        3、设置分页的当前页永远在中间

        当当页大于3的时候整体页数+1

        在这里插入图片描述

        v-for=“i in Math.min(5,totalPage)” :key=“i”>

        实现index函数

        在这里插入图片描述

        index(i){

        if(this.search.page <= 3 || this.totalPage < 5){

        return i;

        }else if(this.search.page >= this.totalPage - 2){

        return this.totalPage - 5 + i;

        }else {

        return i + this.search.page - 3;

        }

        }

        在这里插入图片描述

        在这里插入图片描述

        在这里插入图片描述

        在这里插入图片描述

        4、实现点击分页条实现页面的切换

        (1)实现上一页和下一页的切换
        1)添加点击事件

        在这里插入图片描述

        • <a href=“#” @click.prevent=“prePage” >«上一页

        • ...
        • <a href=“#” @click.prevent=“nextPage”>下一页»

          2)实现对应函数

          在这里插入图片描述

          prePage(){

          if(this.search.page > 1){

          this.search.page–;

          }

          },

          nextPage(){

          if(this.search.page < this.totalPage){

          this.search.page++;

          }

          }

          (2)设置总页数,和总数量
          1)总页数

          在这里插入图片描述

          共{{totalPage}}页 

          在这里插入图片描述

          2)总数量

          在这里插入图片描述

          {{total}} 商品

          {{ search.page }}/{{ totalPage }}

          <a class=“btn-arrow” href=“#” @click.prevent=“prePage” style=“display: inline-block”><

          <a class=“btn-arrow” href=“#” @click.prevent=“nextPage” style=“display: inline-block”>>

          在这里插入图片描述

          (3)(实现点击发送请求刷新数据)监控page的状态如果发生变化就发送请求

          在这里插入图片描述

          watch:{

          search:{//page在search当中

          deep:true,

          handler(){

          if(!oldVal || !oldVal.key){

          return;

          }

          //把请求参数写到URL当中,防止页面刷新的时候page丢失

          location.search = “?” + ly.stringify(this.search);

          }

          }

          },

          在这里插入图片描述

          数据变换成功

          在这里插入图片描述

          三、展示过滤条件


          1、对分类和品牌(进行聚合)

          (1)拓展PageResult,创建SearchResult

          在这里插入图片描述

          在这里插入图片描述

          package com.leyou.search.pojo;

          import com.leyou.common.vo.PageResult;

          import com.leyou.item.pojo.Brand;

          import com.leyou.item.pojo.Category;

          import lombok.AllArgsConstructor;

          import lombok.Data;

          import lombok.NoArgsConstructor;

          import java.util.List;

          @Data

          public class SearchResult extends PageResult {

          private List categories;

          private List brands;

          public SearchResult(){

          }

          public SearchResult(Long total, Integer totalPage, List items, List categories, List brands) {

          super(total, totalPage, items);

          this.categories = categories;

          this.brands = brands;

          }

          }

          (2)修改SearchService的search方法(聚合分类和品牌)

          在这里插入图片描述

          @Autowired

          private ElasticsearchTemplate template;

          在这里插入图片描述

          public PageResult search(SearchRequest request) {

          Integer page = request.getPage() - 1;

          Integer size = request.getSize();

          //创建查询构建器SpringDataElasticSearch - NativeSearchQueryBuilder过滤聚合高亮查询

          NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

          //0 结果过滤

          queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{“id”,“subTitle”,“skus”},null));

          //1 分页

          queryBuilder.withPageable(PageRequest.of(page,size));

          //2 过滤

          queryBuilder.withQuery(QueryBuilders.matchQuery(“all”,request.getKey()));

          //3 聚合分类和品牌

          //3.1集合分类

          String categoryAggName = “category_agg”;

          queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field(“cid3”));

          //3.2对品牌进行聚合

          String brandAggName = “brand_agg”;

          queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field(“brandId”));

          //4 查询

          AggregatedPage result = template.queryForPage(queryBuilder.build(), Goods.class);

          //5 解析结果

          //5.1解析分页结果

          long total = result.getTotalElements();

          int totalPage = result.getTotalPages();

          List goodsList = result.getContent();

          //5.2解析聚合结果

          Aggregations aggs = result.getAggregations();

          List categories = parseCategoryAgg(aggs.get(categoryAggName));

          List brands = parseBrandAgg(aggs.get(brandAggName));

          return new PageResult<>(total,totalPage,goodsList);

          }

          在这里插入图片描述

          (3)完善上述两个方法
          1)添加一个新的API接口对应的方法

          在这里插入图片描述

          @GetMapping(“brand/brands”)

          List queryBrandByIds(@RequestParam(“ids”) List ids);

          2)实现对应的控制层

          在这里插入图片描述

          3)实现brandService

          在这里插入图片描述

          完善前先让BrandMapper继承BaseMapper

          在这里插入图片描述

          完善BrandService当中的queryByIds方法

          在这里插入图片描述

          public List queryByIds(List ids) {

          List brands = brandMapper.selectByIdList(ids);

          if(CollectionUtils.isEmpty(brands)){

          //查询失败抛出自定义的通用异常

          throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);

          }

          return brands;

          }

          4)继续完善ly-search当中的SearchService当中的两个方法

          在这里插入图片描述

          private List parseBrandAgg(LongTerms terms) {

          try {

          List ids = terms.getBuckets()

          .stream().map(bucket -> bucket.getKeyAsNumber().longValue())

          .collect(Collectors.toList());

          List list = brandClient.queryBrandByIds(ids);

          return list;

          }catch (Exception e){

          return null;

          }

          }

          private List parseCategoryAgg(LongTerms terms) {

          try {

          List ids = terms.getBuckets()

          .stream().map(bucket -> bucket.getKeyAsNumber().longValue())

          .collect(Collectors.toList());

          List categories = categoryClient.queryCategoryByIds(ids);

          return categories;

          }catch (Exception e){

          return null;

          }

          }

          5)修改search方法的返回值类型

          在这里插入图片描述

          return new SearchResult(total,totalPage,goodsList,categories,brands);

          6)为了防止手残添加全都的代码

          在这里插入图片描述

          package com.leyou.search.service;

          import com.fasterxml.jackson.core.type.TypeReference;

          import com.leyou.common.enums.ExceptionEnum;

          import com.leyou.common.exception.LyException;

          import com.leyou.common.utils.JsonUtils;

          import com.leyou.common.vo.PageResult;

          import com.leyou.item.pojo.*;

          import com.leyou.search.client.BrandClient;

          import com.leyou.search.client.CategoryClient;

          import com.leyou.search.client.GoodsClient;

          import com.leyou.search.client.SpecificationClient;

          import com.leyou.search.pojo.Goods;

          import com.leyou.search.pojo.SearchRequest;

          import com.leyou.search.pojo.SearchResult;

          import com.leyou.search.repository.GoodsRepository;

          import org.apache.commons.lang.StringUtils;

          import org.apache.commons.lang.math.NumberUtils;

          import org.apache.lucene.util.CollectionUtil;

          import org.elasticsearch.index.query.QueryBuilder;

          import org.elasticsearch.index.query.QueryBuilders;

          import org.elasticsearch.search.aggregations.Aggregation;

          import org.elasticsearch.search.aggregations.AggregationBuilders;

          import org.elasticsearch.search.aggregations.Aggregations;

          import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;

          import org.springframework.beans.factory.annotation.Autowired;

          import org.springframework.data.domain.Page;

          import org.springframework.data.domain.PageRequest;

          import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;

          import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;

          import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;

          import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

          import org.springframework.stereotype.Service;

          import org.springframework.util.CollectionUtils;

          import java.util.*;

          import java.util.stream.Collectors;

          @Service

          public class SearchService {

          @Autowired

          private CategoryClient categoryClient;

          @Autowired

          private BrandClient brandClient;

          @Autowired

          private GoodsClient goodsClient;

          @Autowired

          private SpecificationClient specClient;

          @Autowired

          private GoodsRepository repository;

          @Autowired

          private ElasticsearchTemplate template;

          public Goods buildGoods(Spu spu){

          //查询分类

          List categories = categoryClient.queryCategoryByIds(

          Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));

          if(CollectionUtils.isEmpty(categories)){

          throw new LyException(ExceptionEnum.CATEGORY_NOT_FOND);

          }

          //将categories集合当中所有的name取出来封装为一个字符串集合

          List names = categories.stream().map(Category::getName).collect(Collectors.toList());

          //查询品牌

          Brand brand = brandClient.queryBrandById(spu.getBrandId());

          if(brand == null){

          throw new LyException(ExceptionEnum.BRAND_NOT_FOUND);

          }

          //搜索字段 将字符串集合变成一个字符串以空格为分隔拼接到后面

          String all = spu.getTitle() + StringUtils.join(names," ") + brand.getName();

          //查询sku

          List skuList = goodsClient.querySkuBySpuId(spu.getId());

          if(CollectionUtils.isEmpty(skuList)){

          throw new LyException(ExceptionEnum.GOODS_SKU_NOT_FOND);

          }

          //对Sku进行处理

          List<Map<String,Object>> skus = new ArrayList<>();

          //价格集合

          ArrayList priceList = new ArrayList();

          for (Sku sku : skuList) {

          Map<String,Object> map = new HashMap<>();

          map.put(“id”,sku.getId());

          map.put(“title”,sku.getTitle());

          map.put(“price”,sku.getPrice());

          //截取sku当中图片逗号之前的第一个

          map.put(“images”,StringUtils.substringBefore(sku.getImages(),“,”));

          skus.add(map);

          //处理价格

          priceList.add(sku.getPrice());

          }

          //查询规格参数

          List params = specClient.queryParamList(null, spu.getCid3(), true);

          if(CollectionUtils.isEmpty(params)){

          throw new LyException(ExceptionEnum.SPEC_GROUP_NOT_FOND);

          }

          //查询商品详情

          SpuDetail spuDetail = goodsClient.queryDetailById(spu.getId());

          //获取通用规格参数,获取到通用规格参数的JSON字符串,将其转换为Map集合

          Map<Long, String> genericSpec = JsonUtils.toMap(spuDetail.getGenericSpec(), Long.class, String.class);

          //获取特有规格参数,获取到特有规格参数的JSON字符串,将其转换为Map集合,而Map集合当中的值是String,键为List集合

          Map<Long, List> specailSpec =

          JsonUtils.nativeRead(spuDetail.getSpecialSpec(),

          new TypeReference<Map<Long, List>>(){});

          //处理规格参数,key是规格参数的名称,值是规格参数的值

          Map<String,Object> specs = new HashMap<>();

          for (SpecParam param : params) {

          //规格名称

          String key = param.getName();

          Object value = “”;

          //判断是否是通过规格参数

          if(param.getGeneric()){

          value = genericSpec.get(param.getId());

          //判断是否是数值类型

          if(param.getNumeric()){

          //处理成段

          value = chooseSegment(value.toString(),param);

          }

          }else {

          value = specailSpec.get(param.getId());

          }

          //存入map

          specs.put(key,value);

          }

          //构建good对象

          Goods goods = new Goods();

          goods.setBrandId(spu.getBrandId());

          goods.setCid1(spu.getCid1());

          goods.setCid2(spu.getCid2());

          goods.setCid3(spu.getCid3());

          goods.setCreateTime(spu.getCreateTime());

          goods.setId(spu.getId());

          goods.setAll(all);//搜索字段,包含标题,分类,品牌,规格等信息

          goods.setPrice(priceList);// 所有sku价格的集合

          goods.setSkus(JsonUtils.toString(skus));// 所有sku的集合的JSON格式

          goods.setSpecs(specs);// 所有可以搜索的规格参数

          goods.setSubTitle(spu.getSubTitle());

          return goods;

          }

          private String chooseSegment(String value, SpecParam p) {

          double val = NumberUtils.toDouble(value);

          String result = “其它”;

          // 保存数值段

          for (String segment : p.getSegments().split(“,”)) {

          String[] segs = segment.split(“-”);

          // 获取数值范围

          double begin = NumberUtils.toDouble(segs[0]);

          double end = Double.MAX_VALUE;

          if(segs.length == 2){

          end = NumberUtils.toDouble(segs[1]);

          }

          // 判断是否在范围内

          if(val >= begin && val < end){

          if(segs.length == 1){

          result = segs[0] + p.getUnit() + “以上”;

          }else if(begin == 0){

          result = segs[1] + p.getUnit() + “以下”;

          }else{

          result = segment + p.getUnit();

          }

          break;

          }

          }

          return result;

          }

          public PageResult search(SearchRequest request) {

          Integer page = request.getPage() - 1;

          Integer size = request.getSize();

          //创建查询构建器SpringDataElasticSearch - NativeSearchQueryBuilder过滤聚合高亮查询

          NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

          //0 结果过滤

          queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{“id”,“subTitle”,“skus”},null));

          //1 分页

          queryBuilder.withPageable(PageRequest.of(page,size));

          //2 过滤

          queryBuilder.withQuery(QueryBuilders.matchQuery(“all”,request.getKey()));

          //3 聚合分类和品牌

          //3.1集合分类

          String categoryAggName = “category_agg”;

          queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field(“cid3”));

          //3.2对品牌进行聚合

          String brandAggName = “brand_agg”;

          queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field(“brandId”));

          //4 查询

          AggregatedPage result = template.queryForPage(queryBuilder.build(), Goods.class);

          //5 解析结果

          //5.1解析分页结果

          long total = result.getTotalElements();

          int totalPage = result.getTotalPages();

          List goodsList = result.getContent();

          //5.2解析聚合结果

          Aggregations aggs = result.getAggregations();

          List categories = parseCategoryAgg(aggs.get(categoryAggName));

          List brands = parseBrandAgg(aggs.get(brandAggName));

          return new SearchResult(total,totalPage,goodsList,categories,brands);

          }

          private List parseBrandAgg(LongTerms terms) {

          try {

          List ids = terms.getBuckets()

          .stream().map(bucket -> bucket.getKeyAsNumber().longValue())

          .collect(Collectors.toList());

          List list = brandClient.queryBrandByIds(ids);

          return list;

          }catch (Exception e){

          return null;

          }

          }

          private List parseCategoryAgg(LongTerms terms) {

          try {

          List ids = terms.getBuckets()

          .stream().map(bucket -> bucket.getKeyAsNumber().longValue())

          .collect(Collectors.toList());

          List categories = categoryClient.queryCategoryByIds(ids);

          return categories;

          }catch (Exception e){

          return null;

          }

          }

          }

          7)运行测试

          在这里插入图片描述

          在这里插入图片描述

          http://www.leyou.com/search.html?key=手机&page=4#

          显示分类和品牌

          在这里插入图片描述

          2、对分类和品牌页面渲染并显示

          (1)完善search.html页面代码

          在这里插入图片描述

          filters:[],//过滤项

          在这里插入图片描述

          //商品分类

          this.filters.push({

          k:“cid3”,

          options: resp.data.categories,

          });

          //品牌

          this.filters.push({

          k:“brandId”,

          options: resp.data.brands,

          });

          (2)渲染品牌参数

          删除部分div

          通过观察一下div都是一样的所以删除其他的div只保留一个div

          在这里插入图片描述

          在这里插入图片描述

          在这里插入图片描述

          在这里插入图片描述

          删除其他不是品牌的按照商品分类渲染,是品牌的按照品牌渲染

          在这里插入图片描述

          • 品牌
            • 多选

              开启对应的样式

              在这里插入图片描述

              刷新页面

              在这里插入图片描述

              层渲染规格参数

              1)完善SearchResult添加List<Map<String,Object>>,重新生成对应的构造函数

              在这里插入图片描述

              package com.leyou.search.pojo;

              import com.leyou.common.vo.PageResult;

              import com.leyou.item.pojo.Brand;

              import com.leyou.item.pojo.Category;

              import lombok.AllArgsConstructor;

              import lombok.Data;

              import lombok.NoArgsConstructor;

              import java.util.List;

              import java.util.Map;

              @Data

              public class SearchResult extends PageResult {

              private List categories;//父类的单选项

              private List brands;//品牌集合

              private List<Map<String,Object>> specs;//规格参数过滤条件,key以及待选项

              public SearchResult(){

              }

              public SearchResult(Long total, Integer totalPage, List items, List categories, List brands, List<Map<String, Object>> specs) {

              super(total, totalPage, items);

              this.categories = categories;

              this.brands = brands;

              this.specs = specs;

              }

              }

              2)修改当中的SearchService当中的search方法

              在这里插入图片描述

              //2 过滤

              QueryBuilder baseQuery = QueryBuilders.matchQuery(“all”, request.getKey());

              queryBuilder.withQuery(baseQuery);

              在这里插入图片描述

              List<Map<String,Object>> specs = null;

              if(categories != null && categories.size() == 1){

              //商品父类存在并且数量为1 ,可以聚合参数

              specs = buildSpecificationAgg(categories.get(0).getId(),baseQuery);

              }

              3)完善buildSpecificationAgg方法

              在这里插入图片描述

              private List<Map<String, Object>> buildSpecificationAgg(Long cid, QueryBuilder baseQuery) {

              List<Map<String, Object>> specs = new ArrayList<>();

              //1、查询需要聚合的规格参数(通过商品类型id查询到对应商品的规格参数集合)

              List params = specClient.queryParamList(null, cid, true);

              //2、聚合

              NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

              //2.1带上查询条件

              queryBuilder.withQuery(baseQuery);//将直接的条件添加到当前要查询的条件当中

              //2.2带上查询条件

              for (SpecParam param : params) {//聚合规格参数,通过"specs.“+name+”.keyword"

              String name = param.getName();

              queryBuilder.

              addAggregation(

              AggregationBuilders.terms(name).field(“specs.”+name+“.keyword”)

              );

              }

              //3、获取结果,

              AggregatedPage result = template.queryForPage(queryBuilder.build(), Goods.class);//得到对应的商品聚合

              // 4、解析结果

              Aggregations agss = result.getAggregations();

              for (SpecParam param : params) {

              //规格参数名称

              String name = param.getName();

              StringTerms terms = agss.get(name);//获取规格参数对应的聚合数据

              List options = terms.getBuckets().stream()//将聚合的数据当中的KeyAsString()取出设置为集合

              .map(b -> b.getKeyAsString()).collect(Collectors.toList());

              //准备map(将上述得到的数据设置为map集合)

              Map<String,Object> map = new HashMap<>();

              map.put(“k”,name);

              map.put(“options”,options);

              specs.add(map);

              }

              return specs;

              }

              4)重新运行并测试

              在这里插入图片描述

              刷新页面查看结果

              在这里插入图片描述

              5)将数据渲染到页面上

              在这里插入图片描述

              //2.3其他规格

              resp.data.specs.forEach(spec => this.filters.push(spec) );

              在这里插入图片描述

              刷新页面

              在这里插入图片描述

              6)完善数据为空的时候的

              在这里插入图片描述

            • 发现Vue当中数据没有空的了

              在这里插入图片描述

              (4)实现更多和收起的功能

              在这里插入图片描述

              1)定义控制变量

              在这里插入图片描述

              showMore: false //是否显示更多

              2)设置点击按钮的时候显示或者隐藏

              在这里插入图片描述

              **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

              深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

              因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

              img

              既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

              由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

              如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

              最后

              给大家分享一些关于HTML的面试题,有需要的朋友可以戳这里获取,先到先得哦。


              (o,i) in f.options" :key=“i” v-if=“o”>

              发现Vue当中数据没有空的了

              在这里插入图片描述

              (4)实现更多和收起的功能

              在这里插入图片描述

              1)定义控制变量

              在这里插入图片描述

              showMore: false //是否显示更多

              2)设置点击按钮的时候显示或者隐藏

              在这里插入图片描述

              **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

              深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

              因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

              [外链图片转存中…(img-8q06AeEl-1712454681712)]

              [外链图片转存中…(img-EABdDw7K-1712454681713)]

              既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

              [外链图片转存中…(img-EF6O0S3G-1712454681713)]

              由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

              如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

              最后

              给大家分享一些关于HTML的面试题,有需要的朋友可以戳这里获取,先到先得哦。

              [外链图片转存中…(img-y0frwgd2-1712454681713)]
              [外链图片转存中…(img-qW5PZjo8-1712454681714)]

            • 5
              点赞
            • 7
              收藏
              觉得还不错? 一键收藏
            • 0
              评论

            “相关推荐”对你有帮助么?

            • 非常没帮助
            • 没帮助
            • 一般
            • 有帮助
            • 非常有帮助
            提交
            评论
            添加红包

            请填写红包祝福语或标题

            红包个数最小为10个

            红包金额最低5元

            当前余额3.43前往充值 >
            需支付:10.00
            成就一亿技术人!
            领取后你会自动成为博主和红包主的粉丝 规则
            hope_wisdom
            发出的红包
            实付
            使用余额支付
            点击重新获取
            扫码支付
            钱包余额 0

            抵扣说明:

            1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
            2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

            余额充值