B站尚品汇学习整理笔记(p26-p38)

1、三级联动组件的路由跳转与传递参数

三级联动用户可以点击的有:一级分类、二级分类、三级分类,当点击的时候,Home模块跳转到Search模块,一级会把用户选中的产品(产品的名字、ID)在路由跳转时进行传递。

路由跳转的两种方式:

声明式导航

编程式导航

当使用声明式导航router-link 直接添加给a标签时,虽然可以实现路由的跳转与传参,但是会出现卡顿现象,原因:

router-link是一个组件,当服务器的数据返回之后,会循环出很多的router-link组件(创建组件实例,并将虚拟dom转换成真实dom),在创建组件实例的时候,一瞬间会很耗内存的。

最终解决思路:

1、给类为all-sort-list2 的div添加路由跳转事件,利用事件委派,将事件传给子节点;

2、给子节点里的a标签添加自定义属性data-categoryNamedata-categoryXid ,X为1、2、3,1级菜单的a标签为data-category1id,以此类推。这样的做法是为了让程序确认点击的是a标签,并通过路由,将对应的参数传递给search。因为all-sort-list2 的div子节点有很多种:h3  a  dl   dd  em 都是它的子节点,通过给a绑定独有的属性,然后判断属性data-categoryNamedata-categoryXid是否存在,即可确定点击的是不是a标签、以及是哪一级的a标签。

下为goSearch事件的代码:

goSearch(event){
      // this.$router.push('/search');
      // 最好的解决方案:编程式导航+事件委派
      // 利用事件委派存在的一些问题:1、如何确定点击的一定是a标签;2、如何获取参数(1、2、3级分类的产品名字和id)
      // 把子节点当中a标签加上自定义属性data-categoryName,其余的子节点没有
      let element = event.target;
      //console.log(element);
      // 获取到当前触发这个事件的节点(可能是h3 a dt dl),需要带有data-categoryName这样的节点(一定是a标签)
      // 节点有一个属性dataset 可以获取节点的自定义属性与属性值
      //console.log(element.dataset);
      let {categoryname,category1id,category2id,category3id} = element.dataset;
      // console.log(categoryname);
      // 如果标签身上拥有categoryname,那么一定是a标签
      if(categoryname){
        // 区分是一级分类、二级分类、还是三级分类的a标签
        // 整理路由跳转的参数
        let location ={name:'search'};
        let query={categoryName:categoryname};
        if(category1id){
          // 说明是一级分类a标签
          query.category1Id = category1id;

        }else if(category2id){
          // 说明是二级分类a标签
          query.category2Id = category2id;

        }else{
          // 说明是三级分类a标签
          query.category3Id = category3id;
        }
        location.query=query;
        this.$router.push(location);
      }
    }

总结:这里用到了编程式导航和事件委派,并通过自定义属性来优化性能。

 2、Search模块中商品分类与过渡动画

这里使用了全局组件TypeNav,当页面跳转到search时,需要添加TypeNav的1级菜单的显示与隐藏及动画效果:左边为search 右边为home

                 

可以使用this.$route.path来判断页面跳转的路径,并给对应的div添加一个v-show=‘show’,通过路由来设置该值,从而控制1级菜单的显示与隐藏:

mounted() {
    // 通知Vuex发请求,获取数据,存储于仓库中
    this.$store.dispatch("categoryList");
    // console.log("我是TypeNav,挂载完毕");
    // 当组件挂载完毕,让show的属性变为false
    if(this.$route.path==='/home'){
      this.show=true;
    }else{
      this.show=false;
    }
  },

这里的动画效果,老师是使用vue的过渡动画,需要给过渡动画对应的节点添加一个包裹<transition></transition> ,并添加属性name。对应的动画分为加载前、加载后,下面为代码:

<transition name="sort">
          <!-- 三级联动 -->
          <div class="sort" v-show="show">
            ...
          </div>
</transition>
    // 过渡动画的样式
    .sort-enter{
      height: 0;
    }
    // 过渡动画结束状态
    .sort-enter-to{
      height: 475px;
    }
    .sort-enter-active{
      transition: all .5s linear;
    }

进入/离开 & 列表过渡 — Vue.js

 3、TypeNav商品分类列表的优化

之前将获取TypeNav组件的服务器数据请求放在TypeNav组件中,可以将该请求放在App.vue里。

App.vue里面的代码:

  mounted(){
    // 通知Vuex发请求,获取数据,存储于仓库中,放在这里比放在TypeNav组件中要好,因为当页面发生变化时,TypeNav组件会重新生成,这样会导致用户在切换页面时,反复给后台服务器发送请求,获取数据;而放在App里,则只会当用户刷新整个页面时,才会重新发送请求,相当于优化了代码
    this.$store.dispatch("categoryList");
  }

4、合并参数

对params和query参数的合并:

先需要理解一下用户的操作:

在首页,用户的搜索分为2中情况:

1、点击3级菜单(传入query参数)——跳转到search页面——输入关键字——点击搜索(传入params参数);

2、在home页面搜索栏直接输入关键字——点击搜索(传入params参数);

目前的情况是——

点击3级菜单,query参数有,params参数为空;

点击搜索按钮,params参数有,query参数为空。

上面的情况出现的原因是:目前的两个组件都没有对params参数和query参数做合并,两边在传参的时候,由于都声明了一个单独的location,所以导致这种结果。

解决办法:只需要在传参的时候,判断当前的this.$route中是否存在query参数或params参数即可:

TypeNav组件代码如下:

// 路由跳转到search
    goSearch(event){
      let element = event.target;
      let {categoryname,category1id,category2id,category3id} = element.dataset;
      if(categoryname){
        let location ={name:'search'};
        let query={categoryName:categoryname};
        if(category1id){
          // 说明是一级分类a标签
          query.category1Id = category1id;

        }else if(category2id){
          // 说明是二级分类a标签
          query.category2Id = category2id;

        }else{
          // 说明是三级分类a标签
          query.category3Id = category3id;
        }
        // 判断:如果路由跳转的时候,带有params参数,捎带脚传递过去
        if(this.$route.params){
          location.query=query;
          location.params=this.$route.params; //点击3级菜单时,如果存在params参数,就给location添加上对应的params参数
          this.$router.push(location);
        }
      }

Header组件代码:

goSearch(){
            if(this.$route.query){ // 由于$route的query和params默认为空对象,所以if的条件判断必定为true,不用担心因为不点击3级菜单而导致this.$router.query为undefined
                let location = {
                name:'search',
                params:{keyword:this.keyword ||undefined}
                }
                location.query = this.$route.query; //给location传入之前点击3级菜单后,$route里存放的query参数
                this.$router.push(location);
            }
        }

5、mockjs模拟数据(P32)

开发Home首页当中的ListContainer组件与Floor组件
但是这里需要知道一件事情:服务器返回的数据(接口)只有商品分类菜单分类数据,对于ListContainer组件与Floor组件数据服务器没有提供的。

mock数据(模拟):如果你想mock数据,需要用到一个插件mockjs

Mock.js

此节跳过

6、swiper使用

Swiper使用方法 - Swiper中文网

安装Swiper插件 视频同步选择Swiper5

npm install --save swiper@5

6.1 通过watch+nextTick解决问题

API — Vue.js|vue.$nextTick

watch:{
    // 监听bannerList数据的变化——由空数组变为数组里面有4个元素
    bannerList:{
      handler(newVal,oldVal){
        // 现在咱们通过watch监听bannerList属性的属性值的变化
        // 如果执行handler方法,代表组件实例身上这个属性的属性值已经有了(4个元素的数组)
        // 当前这个函数执行:只能保证bannerList数据已经有了,但是你没办法保证v-for已经执行结束了
        // v-for执行完毕,才有结构,你现在在watch中没办法保证的
        // nextTick:在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的dom
        // 即:bannerList从空数组变成4个元素的数组后(bannerLinst的数据发生了修改),且v-for循环完成后,会执行nextTick里面的回调函数,确保了mySwiper实例是在页面存在结构后才生成的,保证了swiper的功能正常使用。
        this.$nextTick(function(){
          var mySwiper = new Swiper ('.swiper-container', {
          // direction: 'vertical', // 垂直切换选项
          loop: true, // 循环模式选项
          
          // 如果需要分页器
          pagination: {
            el: '.swiper-pagination',
            // 点击小球也可以进行切换
            clickable:true
          },
          
          // 如果需要前进后退按钮
          navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
          },
          
          // 如果需要滚动条
          scrollbar: {
            el: '.swiper-scrollbar',
          },
        });
        })
      }
    }
  }

$nextTick可以保证页面中的结构一定是存在的,经常和很多的插件一起使用【很多插件都需要DOM存在才能正常工作】

7、获取floor组件mock数据

关键点:

1、根据floor组件的mock数据可知,获取数据需要在Home路由组件当中获取;

2、v-for也可以在自定义标签中使用;

组件间通信方式有哪些

props:用于父子组件通信(面试频率极高)

自定义事件:$on $emit 可以实现子给父通信

全局事件总线:$bus 全能

pubsub-js :vue中几乎不用 react用的比较多

插槽:3种

vuex


另外需要注意:Floor组件的Swiper实例可以直接在mounted中引入,原因如下:

//第一次书写Swiper的时候:在mounted当中书写是不可以的,但是为什么现在这里可以啦!
//第一次书写轮播图的时候,是在当前组件内部发请求、动态渲染解构【前台至少服务器数据需要回来】,因此当年的写法在这里不行//现在的这种写法为什么可以:因为请求是父组件发的,父组件通过props传递过来的,而且结构都已经有了的情况下执行mounted


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值