尚品汇前端项目总结2(P31-P59)

目录

从Home跳转到search

优化typenav的数据请求

合并params和query参数 

Home首页的开发

mock.js

$nextTick解决swiper使用的问题(项目难点2)

homeFloor组件开发

数据获取

轮播图

search模块开发

 请求数据以及Vuex

面包屑

排序

分页器(自己封装的单独组件,还有轮播图组件)

分页器需要的数据

分页器起始与结束数字计算

分页器动态展示

动态添加类名

将子组件中选择的页码传回父组件


从Home跳转到search

优化typenav的数据请求

在home和search组件中的typenav组件都在mounted的时候请求了同一组数据,在切换路由的时候会反复重新申请,所以可以把请求的动作放在根目录(App.vue)的mounted里面,并且用props传递参数这样就只会请求一次,不能放在main.js里面,虽然他也是执行一次,但是只有组件身上才有$store属性

合并params和query参数 

去search组件有两个方法:分类列表与搜索框,分类列表带过去的时query参数,搜索框带过去的时params参数, 传递参数之前做一个判断,如果从分类列表过去,看原本的params有没有参数,有参数就将这个参数一起带过去,从搜索框过去也是一样。

为什么要分别用query和params参数?因为这样就可以同时有两种方式的keyword

Home首页的开发

mock.js

mock数据(模拟后台数据) 用mockjs  mock的数据不会和服务器进行通信。拦截ajax请求

使用步骤:

1、在src目录下创建mock文件

2、准备JSON数据,在mock文件中创建相应的JSON文件   一定要格式化,不能有空格

3、把mock数据需要的数据放在public文件夹中,因为public文件夹在打包的时候会原封不懂把资源打包到dist文件夹里面

4、创建mockServer.js开始mock虚拟数据源,通过mockjs模块实现

        1)引入mock import Mork from ‘mockjs

        2)引入json数据(json数据格式和图片是默认对外暴露的

        3)Mock.mock(‘路径(这里是指接口路径).{code:200,data:数据})

Mock.mock( rurl, template ):记录数据模板。当拦截到匹配 rurl 的 Ajax 请求时,将根据数据模板 template 生成模拟数据,并作为响应数据返回。

5、mockServer.js文件在入口文件(main.js)中引入(至少执行一次,才能模拟数据)

参考内容

补充:前端mock数据的方法

$nextTick解决swiper使用的问题(项目难点2)

最新版本可能会有问题,这里安装的是5版本,使用方法可以上官网查询

只引入样式的时候只要import路径就可以了

要new swiper 必须要先有样式结构,因为new swiper的时候要操作DOM 

如果上面用了v-for并且从仓库获取数据,修改仓库中的数据在new swiper后面(因为ajax请求是异步的),所以new swiper的时候结构还没有生成,导致不能正常使用

  1. update:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子但是只要任何数据更新,都会重新执行
  2. 加一个定时器,使new swiper在仓库更新后执行
  3. watch加$nectTick:能够保证函数在由于watch监听的数据的变化所进行的DOM更新完毕之后执行

watch:监听已有数据的变化,监听组件实例身上的属性的属性值的变化,有对象的写法和函数的写法

watch中的immediate:true代表立即监听,不论数据有没有变化,上来就立即监听一次

对象写法里面hander(newValue,oldValue)函数,把new swiper放里面只能保证此时数据已经发生变化但是不能保证v-for执行完毕

$nextTick:在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的DOM【$nextTick:能够保证DOM已经更新】

homeFloor组件开发

数据获取

获取homefloor数据的时候要在home组件里面dispatch因为有两个homefloor,要v-for遍历(v-for也能够在自定义标签当中),然后用使用props传递数据

组件间通信方式有那些?

1)props:用于父传子组件之间

2)自定义事件@on @emit  在父组件定义自定义事件在子组件标签上加@自定义事件,在子组件中用this.$emit.自定义事件触发

3)全局事件总线$bus  全能

4)pubsub-js vue中几乎不用 全能

5)插槽

6)vuex

轮播图

homeFloor中的轮播图:因为是在home组件中发的getfloor请求,所以在floor组件中已经有完整的数据传入,所以直接在mounted中new swiper

把轮播图拆分成一个组件,复用结构,以后在页面中的复用结构最好弄成全局组件

search模块开发

 请求数据以及Vuex

1)Post方式请求,传递参数至少是个空对象 可以用params={},每传递参数的时候就默认是个空对象,有参数就用参数

//接口设置
export const reqSearch = ((params) => {
        return requests({ url: '/list', method: 'post', data: params })
    })
const actions = {
    async getSearch(context, params = {}) {
        let result = await reqSearch(params);
        // console.log(result)
        if (result.code == 200) {
            context.commit('GETSEARCH', result.data)
        }
    }
};

2)Getters可以简化state中的数据,return的时候要注意,如果没有state中没有数据那么return的会是undefine会出现错误,所以最好||[]传递一个空数组

3)因为search中根据输入的参数不同要发不同的请求,所以请求不能放在mounted里面可以把请求封装成函数,在需要的时候进行调用

4)在组件挂载之前(就是在获取后台数据之前)修改传递的参数,可以在mounted,created

beforemouted里面

5)合并对象:es6新增  用Object.assign(1,2,3) 会对比1与23之间的key如果23中有key与1一样就会替换掉1

beforeMount(){
    Object.assign(this.searchInfo,this.$route.query,this.$route.params);
},

6)监听路由变化再次发送请求获取数据:

 watch:{
      $route:{
        handler(newV,oldV){
          Object.assign(this.searchInfo,this.$route.query,this.$route.params)
          this.getSearch();
          //因为这些可能不会被覆盖掉
          this.searchInfo.category1Id='';
          this.searchInfo.category2Id='';
          this.searchInfo.category3Id='';
        }
      }
    }

面包屑

面包屑有四个种类

前三个用v-if或者v-show,有则显示无则隐藏,最后一个用v-for因为可能不止一个 

一、全部商品分类中的标签(query参数)

点击面包屑上的删除按键的时候,要将对应的标签对应的参数设置为undfined,注意对应的id也要置为undfined【设置成undefined的属性不会被传给服务器,能够节省内存,设置成空一样会被传】

 removeCategoryName(){
        //设置成undefine就不会被传过去,能够节省内存
        this.searchInfo.category1Id=undefined;
        this.searchInfo.category2Id=undefined;
        this.searchInfo.category3Id=undefined;
        this.searchInfo.categoryName=undefined;
        //地址栏也需要修改
        this.$router.push({name:'search',params:this.$route.params});
        
      },

地址路径也需要修改,进行路由跳转,因为标签对应的是query参数,此时query参数已经没有了,所以只要携带params参数就行。

二、搜索框输入的关键字(params参数)

点击删除面包屑,除了清除关键字,还要清除搜索栏上的字,利用全局事件总线清除

      removeKeyword(){
        //设置成undefine就不会被传过去,能够节省内存
        this.searchInfo.keyword=undefined;
        this.$bus.$emit('clear');
        //地址栏也需要修改
        this.$router.push({name:'search',query:this.$route.query});
        
      }

配置全局事件总线:

在main中的beforecreate中写Vue.prototype.$bus=this

然后在需要被修改的组件里面绑定this.$bus.$on(‘事件名’,()=>{}),mounted里面,在触发的组件里面写this.$bus.$emit(‘事件名)

三、品牌名称

添加面包屑:

在search的子组件searchselector里面,利用自定义事件来通信

在子组件里面触发事件this.$emit

//子组件
trademarkInfo(trademark){
    this.$emit('trademarkInfo',trademark); 
}

父组件在子组件的标签上绑定自定义事件

//父组件
 <SearchSelector @trademarkInfo="trademarkInfo"/>

 父组件中修改参数

      trademarkInfo(trademark){
        this.searchInfo.trademark=`${trademark.tmId}:${trademark.tmName}`;
      },

展示面包屑

 <li class="with-x" v-if="searchInfo.trademark" >{{searchInfo.trademark.split(':')[1]}}<i @click="removeTrand">×</i></li>

点击删除该面包屑,清空品牌名

      removeTrand(){
        this.searchInfo.trademark=undefined;
        this.getSearch()
      }

四、平台售卖属性

 添加与删除方法和三差不多,但是因为是数组,不是单个值,所以要根据索引值从数组中删除相应的属性值

 removeattr(index){
        this.searchInfo.props.splice(index,1);
        this.getSearch()
      }

排序

searchInfo中代表排序的属性为"order": "1:desc",1代表综合,2代表价格,desc代表降序,asc代表升序。

对应地设置了四个计算属性来代表这四个值,再根据这四个值来判断是否显示类,以及箭头是否显示,指示的是上还是下(动态类)

<span v-show="isOne" class="iconfont" :class="{'icon-download':isDown,'icon-upload':isUp}"></span>

Iconfont使用:上网站将需要的图标加入购物车,下载或复制在线链接,在public的index.html里面link引入,记得加协议,然后在要使用的地方添加类名iconfont和类名(图标名)

当点击价格或综合标签的时候进行的一些逻辑:

首先获取原来是排序状态,flag代表是点击了价格还是综合,原来的标签和现在的标签一样就不变标签,但是修改箭头的方向,如果变了就改变标签并且为降序,最后再次请求数据

changeActiveOne(flag){
        let orginFlag=this.searchInfo.order.split(':')[0];
        let orginDeriction=this.searchInfo.order.split(':')[1];
        if(flag==orginFlag){
          this.searchInfo.order=`${flag}:${orginDeriction=="desc"?"asc":"desc"}`;
        }else{
          this.searchInfo.order=`${flag}:desc`;
        }
        this.getSearch()
      }

分页器(自己封装的单独组件,还有轮播图组件)

因为数据很多,所以展示的时候会用到分页器

分页器需要的数据

pageNow:当前是第几页

pageSize:每一页展示多少数据

totalPages:一共有多少页

continus:连续的页码数,即分页器中显示的页码,其他部分用...隐藏,一般是5或者7,因为这样的话会对称

这些数据都通过props从父组件传到分页器子组件

<Pagination :pageNow=searchInfo.pageNo :pageSize=searchInfo.pageSize :total=total :continues="5" @changePage="changePage"/>

分页器起始与结束数字计算

通过计算属性来计算要展示的页码区间

首先计算出要显示当前页的前后几页before,after

分为几种情况:

1)如果totalPages小于continues,那么start=1,end=totalPages

2)如果当前页的前before页小于1,那么start=1,end=continues

3)如果当前页的后after页大于totalPages,那么start=totalPages-continues+1,end=totalPages

4)其余情况下start=pageNow-before,end=pageNow+after

5)将start和after之间的数组成数组,并返回

showPages(){
          const {continues,totalPages,pageNow}=this;
          let start=0,end=0;
          let before=Math.floor(continues/2);
          let after=continues-Math.floor(continues/2)-1;
          let showArr=[];
          if(continues>totalPages){
            start=1;
            end=totalPages;
          }else if(pageNow-before<1){
            start=1;
            end=continues;
          }else if(pageNow+after>totalPages){
            start=totalPages-continues+1;
            end=totalPages;

          }else{ start=pageNow-before;
            end=pageNow+after;}
        for(let i=start;i<=end;i++){
          showArr.push(i)
        }
          return {showArr,end,start}
        },

分页器动态展示

v-for可以遍历数字

标签分为八个button:上一页、页码1、【...】、中间页码、【...】、最终页码、下一页、共有几页

标签的显示与隐藏:

页码1:当start>1的时候显示

【...】:当start>2的时候显示

【...】:当end<totalPages-1的时候显示

最终页码:当end<totalPages的时候显示

动态添加类名

当前页为标签名的时候动态添加active类名

并且当页码为1的时候禁用上一页,页码为totalPages的时候禁用下一页

将子组件中选择的页码传回父组件

用自定义事件,当修改页码的时候$emit触发修改当前页码 

<div class="pagination">
   <button @click="$emit('changePage',pageNow-1)" :disabled="pageNow==1">上一页</button>
   <button :class="{active:pageNow==1}" v-show="showPages.start>1" @click="$emit('changePage',1)" >1</button>
   <button v-show="showPages.start>2">...</button>
   <button :class="{active:pageNow==p}" v-for="(p,index) in showPages.showArr" :key="index" @click="$emit('changePage',p)">{{p}}</button>
   <button v-show="showPages.end<totalPages-1">···</button>
   <button :class="{active:pageNow==totalPages}" v-show="showPages.end<totalPages" @click="$emit('changePage',totalPages)">{{totalPages}}</button> 
   <button @click="$emit('changePage',pageNow+1)" :disabled="pageNow==totalPages">下一页</button>
   <button style="margin-left: 30px">共{{total}}条</button>
</div>
//父组件中的方法     
 changePage(page){
         this.searchInfo.pageNo=page;
         this.getSearch()
      }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值