doumian

项目需求分析

1 项目前期准备工作

1. cli搭建项目
2.css样式导入 公共资源图片等的导入
3.别名的配置和代码规则
    <script>
   module.exports = {
 configureWebpack: {
   resolve: {
     alias: {
       \'assets\': \'@/assets\',
       \'common\': \'@/common\',
       \'components\': \'@/components\',
       \'network\': \'@/network\',
       \'views\': \'@/views\',
    }
  }
}
  </script>
<script>
   root = true
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
</script>

2 底部导航栏封装

3 Home 顶部导航栏封装(因我在其他的页面中也有这个组件)

4 Home组件首页轮播图组件导入

5 安装axios 网络封装

    <script>
   import axios from \'axios\'
export function request(config) {
 // 1.创建axios的实例
 const instance = axios.create({
   baseURL: \'http://123.207.32.32:8000/api/h8\',
   //baseURL: \'http://106.54.54.237:8000/api/v1,
   timeout: 5000
})

 // 2.axios的拦截器
 // 2.1.请求拦截的作用
 instance.interceptors.request.use(config => {
   return config
}, err => {
   // console.log(err);
})

 // 2.2.响应拦截
 instance.interceptors.response.use(res => {
   return res.data
}, err => {
   console.log(err);
})

 // 3.发送真正的网络请求
 return instance(config)
}

6 在组件刚一创建的时候就发送网络请求,在created生命周期函数进行网络请求

轮播图数据展示/推荐数据展示/流行数据展示(feature)

7 Tab\'Cont\'rol业务分析 因为在其他页面还有使用 应该是在业务组件中

8 请求首页goods数据

点击3个不同的按钮请求不同的数据,首页列表数据请求保存

goods: {
   \'pop\': {page: 1, list:[]},
   \'new\': {page: 1, list:[]},
   \'sell\': {page: 1, list:[]}
}
//发送HomeGoods商品列表数据  需要进行参数传递  
export function getHomeGoods(type, page) {
 return request({
   url: \'/home/data\',
   params: {
     type,
     page
  }
})
}
//请求数据
getHomeGoods(\'pop\',1).then(res => {
     console.log(res);
})
8.1如何点击不同tabControl 请求不同的数据

 // 2 请求homeGoods商品数据
   this.getHomeGoods(\'pop\')
   this.getHomeGoods(\'new\')
   this.getHomeGoods(\'sell\')

getHomeGoods(type) {
     const page = this.goods[type].page + 1
     getHomeGoods(type,page).then(res => {
     // console.log(res.data.list);
     this.goods[type].list.push(...res.data.list)
     this.goods[type].page += 1
  })
}
8.2对商品列表分析,和业务相关 而不是公共组件了

 

然后把数据传递到goodsList goodsListItem

9 引入better-scroll 解决在移动端滚动卡顿问题

需求: 为了减少对better-sroll的依赖,对better-scroll 进行封装 而且在多数页面需要用到,在公共组件进行创建创建,将引用插件进行封装成一个组件,那里需要进行导入这个组件即可,后期维护也方便,逻辑也i清晰

better-scroll安装:
 1. 终端通过npm安装: npm install better-scroll --save 
<template>
 <div class="wrapper" ref="wrapper">
   <div class="content">
     <slot></slot>
   </div>
 </div>
</template>

<script>
import BScroll from \'better-scroll\'
export default {
 data() {
   return {
     scroll: null
  }
},
 props: {
   probeType: {
     type: Number,
     default() {
       return 0
    }
  }
},
 mounted() {
   //1 创建BScroll实力对象
   this.scroll = new BScroll(this.$refs.wrapper, {
     click: true,
     probeType: this.probeType  //默认为不触发scroll滚动事件,那个页面需要进行传值即可,这样性能也大大提高
  })

滚动原理:

 

10 点击backTop按钮返回Home顶部

需求:

 

需求分析:
  1. 首先该功能会在页面滚动某个临界值进行显示或隐藏,其次不会随着页面滚动而滚动,所以简单方法进行fixed 固定定位

  2. 对页面需要进行实时监听滚动位置

  3. 该需求是在Home 首页组件进行监听,也就是需要对backTop这个组件进行监听

下面进行代码实现:
  1. 新建BackTop组件,引入一张箭头图片,如下

    <template>
     <div class="back-top" >
       <img src="~assets/img/common/top.png" alt="">
     </div>
    </template>
    <script>
    export default {
    }
    </script>
    <style scoped>
    .back-top {
     position: fixed;
     right: 8px;
     bottom: 50px;
    }
    .back-top img {
     width: 42px;
     height: 42px;
    }
    </style>
  2. 在Home首页组件导入并注册:(需要注意的是这个组件是不需要随着滚动的)

  3. 对这个组件进行事件点击监听 --------组件监听需要用到事件修饰符native(这里也可以在backTop组件内部进行点击事件,然后把这个事件发送出来在进行监听,这样做不过相对繁琐,还多写了代码)

    ![1587051148799](C:\Users\NB\AppData\Roaming\Typora\typora-user-images\1587051148799.png)

    然后通过ref拿到scroll这个组件调用scrollTo()这个方法

     backTopClick() {
         // console.log(this.$refs.scroll.scroll);
         // this.$refs.scroll.scroll.scrollTo(0, 0, 400);
         this.$refs.scroll.scrollTo(0, 0, 400);
    }

    //scrollTo(x, y, time, easing)
    //参数:
    //{Number} x 横轴坐标(单位 px)
    //{Number} y 纵轴坐标(单位 px)
    //{Number} time 滚动动画执行的时长(单位 ms)
    //{Object} easing 缓动函数,一般不建议修改,如果想修改,参考源码中的 ease.js 里的写法
    //返回值:无
    //作用:滚动到指定的位置,引用:https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/api.html#scrolltox-y-time-easing
    //this.$refs.scroll.scroll.scrollTo(0, 0, 400)
    //此代码不方便阅读,对奇进行封装,把插件scrollTo()封装到组件scrollTo中 看代码吧 这样更清楚

4.对Home页面滚动进行实时监听,而我们封装的BScroll滚动插件是scroll这个组件,这里需要在scroll组件进行监听,然后把这个事件发送出了

 mounted() {
   //1 创建BScroll实力对象
   this.scroll = new BScroll(this.$refs.wrapper, {
     click: true,
     probeType: this.probeType
  }),
   //发送事件监听事件
   this.scroll.on(\'scroll\', (position) => {
     // console.log(position);
     this.$emit(\'scroll\',position)
  })
}

然后在首页接受这个事件,设置一个变量控制backTop显示隐藏

 contentScroll(position) {
     console.log(position);
     this.isShow = -position.y > 1300 ? true : false
}

 目前代码效果:

 

 

11 点击商品列表进入商品详情页

分析: 每个商品都有不同id,所以在点击每个goodslistitem,我们需要拿到这个唯一的商品id,去后台接口请求对应的商品数据,然后在进行展示,而且从home也跳转到详情页,我们使用路由就可以

1 对goodslistitem进行点击事件,并将商品id传过去
goodsItemClick() {
     console.log(\'111\',this.goodsitem.iid);
     this.$router.push(\'/detail/\'+ this.goodsitem.iid)
}

//路由跳转传参 可以有2种方式 1 动态路由 2 query方式
goodsItemClick() {
     // console.log(\'-----\',this.goodsitem.iid)
     //动态路由
     this.$router.push(\'/detail/\'+ this.goodsitem.iid)
     //query方式
     this.$router.push({
       path: \'/detail\',
       query: {
         iid: this.goodsitem.iid
      }
    })
  }

//路由配置方式也不一样
{
   path: \'/detail/:iid\', //动态路引
   component: Detail
},
{
   path: \'/detail\',    //query方式
   component: Detail
}

//获取iid方式
this.iid = this.$route.params.iid
this.iid = this.$route.query.iid
// 另外在url中显示也有差异 如下

2 拿到iid在network请求数据,为了方便后期维护 阅读,我们单独新建详情页网络请求 dedtail.js
import {request} from \'./request\'

export function getDetail(iid) {
 return request({
   url: \'/detail\',
   params: {
     iid
  }
})
}
之后在Detail组件刚一创建出来created生命周期函数进行网络请求

12 上拉加载更多

在封装好的 BScroll 中 调用上拉加载更多事件,然后把这个事件发送出来,然后在home页 执行并调用finishPullUp()

 //上拉加载更多
   this.scroll.on(\'pullingUp\',() => {
     // console.log(\'上拉加载更多\');
     this.$emit(\'pullingUp\')
     // this.scroll.finishPullUp()
  })

home页进行监听

 //上拉加载更多
   pullUpClick() {
     // console.log(\'上拉加载\');
     this.getHomeGoods(this.currentType)
     this.$refs.scroll.finishPullUp()
  },

13 解决首页 详情页 滚动卡顿问题

  • 分析:
  • 主要原因是图片加载影响 better-scroll计算可滚动区域问题,不能滚动的问题主要是因为图片加载完成后,这个时候better-scroll得到可滚动区域height,没有刷新,所导致

  • 我们对每一张加载图片进行监听 ,只要有一张图片你加载完成,我们就重新计算一次Bscroll的高度

    • 如何监听图片加载完成

      • 原生js监听 img.load = () => {}

      • Vue提供的加载方式 @load=() => {}

    • 然后调用better-scroll的refresh()

      //refresh()
      //参数:无
      //返回值:无
      //作用:重新计算 better-scroll,当 DOM 结构发生变化的时候务必要调用确保滚动的效果正常。
  • 这里涉及到非父子组件事件通信,我们可以使用Vuex或者事件总线 这里我们先使用事件总线

  • 1 事件总线使用方法:
    • main.js入口文件 挂载到Vue原型实例上,全局任何地方都可以使用

    • Vue.prototype.$bus = new Vue()
    • 发送事件

    • this.$bus.$emit(\'itemImageLoad\',params)// 事件函数, 参数
    • 接收事件

    • this.$bus.$on(""callback)  // 事件函数 回调函数  一般是组件运行阶段,mounted函数中执行
    • 取消事件

    • this.$bus.$off(""callback)  // 事件函数 回调函数  取消事件是组件是否有keep-alive  有选择deactivated 否destroyed中
  • 2 使用Vuex进行非父子组件通信
    • 先创建·1一个变量,对这个变量植进行watch监听,每加载一张图片,变量植发生改变

14 实现详情页上下联动联动效果,点击对应标题滚动到对应的位置和内容滚动显示正确标题

  • 效果图:

  • 点击标题跳转到对应位置

    • 每给标题对应一个值,只要我们拿到这个值,在点击标题的时候,调用scrollTo就可以滚 动到对应位置,所以我们新建一个数组,来保存offsetTop

    • 首先对详情页 标题 进行监听

    • 获取 详情页 所有组件的offsetTop

      • 如何获取 不同组件 的offsetTop

        • 首先我们会想到在mounted中获取offsetTop,然而获取的值完全不对,甚至出现了undefined

        • mounted() {
             console.log(\'-----\')
             this.themeTops = [];
             this.themeTops.push(0);
             this.themeTops.push(this.$refs.paramsinfo.$el.offsetTop);
             this.themeTops.push(this.$refs.commentinfo.$el.offsetTop);
             this.themeTops.push(this.$refs.recommend.$el.offsetTop);
             console.log(this.themeTops);
          },
          //[0, undefined, 498, 626, __ob__: Observer]
        • 值获取不正确,首先想到的是图片影响,之前我们有对图片的加载进行监听,图片加载完成后,我们再获取offsetTop值

        • //对详情页图片监听
             detailImageLoad() {
               //获取参数 评论 推荐的offsetTop值
               this.themeTops = [];
               this.themeTops.push(0);
               this.themeTops.push(this.$refs.paramsinfo.$el.offsetTop);
               this.themeTops.push(this.$refs.commentinfo.$el.offsetTop);
               this.themeTops.push(this.$refs.recommend.$el.offsetTop);
               console.log(this.themeTops);
                 
               this.$refs.scroll.refresh();
            },
          // 打印结果 [0, 9289, 10031, 10180, __ob__: Observer]
        • 然后调用scrollTo方法

        • titleClick(index) {
              // console.log(index);
              this.$refs.scroll.scrollTo(0, -this.themeTops[index], 300)
          },
    • 内容滚动显示正确标题

      • 分析: 我们需要实时对页面滚动进行监听 ,在better-scroll中把scroll这个事件发送出来,我们在Detail进行接受这个事件

      • 通过获取到posiiton.y 和之前获取到 this.themeTops这个数组中4个值进行比较 然后动态改变标题

14 Vue原生上下联动或左右联动效果

  • 上下联动或左右联动效果非常常见 但是我们平时大多使用封装好的UI工具库,直接按需导入安装,这里我们不使用插件和UI

  • 这里我们主要简单建立三个组件

  • 1 点击ShopTitles中小titles 让活跃title显示背景颜色 其他不变,这个相对简单

  • 2 点击不同title让右边的Shop组件跳转到不同位置

    • 1 首先要监听SHop组件的滚动,其次调用JS原生滚动方法 scroll

    • 2 对Shop组件添加滚动事件 需要注意的是 addEventListener第三个参数为true  ,

    • 3 父元素 overflow不能是hidden,而是scroll,要不然子元素滚动不了 (当然子元素内容高度高于父元素高度)

//父组件
<template>
 <div class="category">
  <div class="nav-bar" >
    <div class="nav"> 我是顶部的商品展示区域</div>
  </div>
  <shop-titles :titles="titles" @titleClick="titleClick" ref="titles"/>
  <shop ref="shop" @shopOpsitons="shopOpsitons" />
 </div>
</template>

<script>
import Shop from \'components/common/shop/Shop\'
import ShopTitles from \'components/common/shop/ShopTitles\'
export default {
 name: \'Category\',
 data() {
   return {
     titles:[\'热卖\',\'特色精品\',\'精选热菜\',\'热卖\',\'特色精品\',\'精选热菜\'],
     shopScrollTop:[0, 300, 600, 900, 1200, 1500],
     current: 0
  }
},
 components: {
   Shop,
   ShopTitles
},
 mounted() {
 
},
 methods: {
  titleClick(index) {
    this.$refs.shop.$el.scrollTo({left: 0, top: this.shopScrollTop[index],behavior: \'smooth\'})
  },
 shopOpsitons(saveY) {
   // console.log(saveY)
   const Max = Number.MAX_VALUE;
   this.shopScrollTop.push(Max);

   const length = this.shopScrollTop.length;
   for( let i = 0; i < length; i++) {
     if((this.current !== i)&&(saveY >= this.shopScrollTop[i] && saveY < this.shopScrollTop[i+ 1])) {
       this.current = i
       this.$refs.titles.currentIndex = this.current
    }
  }
   
}
}
}
</script>
<style scoped>
.category {
 height: 100vh;
}
.nav-bar {
 width: 100%;
 border-bottom: 2px solid #333;
 height: 160px;
 margin: 20px 0;
 position: fixed;
 z-index: 10;
}

分类:

技术点:

相关文章: