vue2项目(三)----- Home

 Home页面有7个子组件。

1. TypeNav三级联动组件,在home,search,detail组件都在使用,所以可以注册为全局组件,这样只需要注册一次,就可以在项目的任意地方使用。

步骤:

1)创建组件(命名为TypeNav,全局组件一般放在components文件夹中)

 2)全局注册组件(在main.js文件中)

// 三级联动组件(全局组件)
import TypeNav from './components/TypeNav'
// 全局组件:第一个参数是全局组件的名字,第二个参数是哪个组件
Vue.component(TypeNav.name,TypeNav)

3)使用组件(在home组件中使用TypeNav)

  2. 完成其余的组件

步骤一样,先创建组件,再在Home组件中引入和注册并使用

 说明:

1)本项目是一个前后台分离的项目: 前台应用与后台应用

2)后台应用负责处理前台应用提交的请求, 并给前台应用返回json数据

3)前台应用负责展现数据, 与用户交互, 与后台应用交互

 3. 前后端交互AJAX

1)先安装axios

npm install -S axios nprogress

2)axios一般存放在api文件夹(自己创建)里面

index.js---对api进行统一管理

ajax.js---二次封装axios

二次封装的原因:在本项目中需要使用到请求拦截器和响应拦截器

请求拦截器:在发请求之前处理一些业务

响应拦截器:在服务器数据返回后,处理一些事情

在/api/ajax.js
// 二次封装axios
import axios from 'axios'

const service = axios.create({
    baseURL: '/api',//基础路径
    timeout: 15000//连接请求超时时间
})

// 请求拦截器
service.interceptors.request.use((config) => {
    // 必须返回配置对象
    return config;
})

// 响应拦截器
service.interceptors.response.use(
   (response) => {
    // 返回响应体数据
    return response.data
}, (error) => {
    // 统一处理一下错误
    alert(`请求出错: ${error.message || '未知错误'}`)
    // 后面可以选择不处理或处理
    return Promise.reject(error)
})

export default service

3)api接口的统一管理

项目很小:可以在组件的生命周期函数里发请求

项目大:使用axios.get('xxx')

// 对接口的统一管理
import ajax from './ajax.js'

// 获取商品的三级分类列表
// /api/product/getBaseCategoryList  get 无参数
export const reqBaseCategoryList=()=>{
    return ajax({url:'api/product/getBaseCategoryList',method:'get'})
}
// export const reqBaseCategoryList=()=>ajax.get(`api/product/getBaseCategoryList`)

4)引入进度条

先安装cnpm install --save nprogress

4.vuex模块化开发

注意:

1)vue2使用vuex3 , vue3使用vuex4

2)项目小的,可以不用vuex;项目大的,组件多的,需要使用vuex

操作流程:给每一个模块创建小仓库,再把小仓库引入到大仓库中

步骤:

1)先创建大仓库(store/index.js),再创建小仓库(store/home.js)

//在store/home.js中
import { reqBaseCategoryList } from '@/api'
const home={
    state:{
        baseCateGoryList:[]
    },
    mutations:{
        RECEIVE_BASE_CATEGORY_LIST(state,list){
            list.shift()//去除数组的第一个元素
            state.baseCateGoryList=list
        },   
    },
    actions:{
        async getBaseCateGoryList({commit}){
            const result=await reqBaseCategoryList()
            if(result.code==200){
                commit('RECEIVE_BASE_CATEGORY_LIST', result.data)
            }
        }
    },
    getters:{},
    namespaced:true
}
export default home

2)在大仓库里引入小仓库home 

在store/index.js
// 大仓库
import Vue from 'vue'
import Vuex from 'vuex'
// 需要使用插件一次
Vue.use(Vuex)

import home from './home'
// 对外暴露store类的一个实例
export default new Vuex.Store({
// 实现Vuex仓库模块化开发存储数据
modules:{
    home,  
    }
})

3)在main.js中,引入store

// 引入仓库
import store  from './store'

new Vue({
  render: h => h(App),
  
  // 注册路由
  router:router,
  // 注册仓库:
  store
}).$mount('#app')

 5. 实现TypeNav三级动态联动(向服务器发送请求,获取数据,进行展示)

1)当组件挂载完毕后,可以向服务器发送请求

//在TypeNav/index.vue中

mounted(){
    this.$store.dispatch('home/getBaseCateGoryList')
 },

2)去home仓库请求数据

actions在执行时,会调用api里面的接口函数,向服务器发请求,调用api里的reqBaseCategoryLis函数发送。

请求成功后,把数据给mutations处理。

再把数据给state。

3)TypeNav接收数据

4)渲染数据

注意
1. home仓库使用了namespaced,开启了命名空间,在使用仓库时,记得添加/home
2. 在使用vuex模块化时,需要向外暴露一个对象,不需要用到createStore。所以给home里面命名一下,并向外暴露。
3.注意vuex3和vuex4的区别 。

6. 给三级联动的一级分类添加背景颜色,二三级进行显示与隐藏

步骤:

1)首先设置一个动态属性 currentindex=-1 ,表示鼠标都没有移上去。

//在TypeNav/index.vue中
data() {
    return {
      // 响应式属性,存储用户鼠标移上哪一个一级分类
      currentIndex: -1, // 代表鼠标谁都没有移上去
    };
},

2) 添加一个less属性,设置背景颜色

3)给一级分类添加鼠标进入和离开事件。进入时,需要携带参数索引号,表示是哪一个一级分类。

:class="{cur: currentIndex === index} 为真时,就给当前的一级分类添加背景颜色。

//在TypeNav/index.vue中  
<div class="item"  v-for="(c1, index) in baseCateGoryList"  :key="c1.categoryId"  
      @mouseleave="leaveIndex">
  <h3 @mouseenter="changeIndex(index)"  :class="{ cur: currentIndex === index }" >
      <a>{{ c1.categoryName }}</a> 
  </h3>
</div>



methods: {
    // 鼠标进入修改响应式数据currentIndex属性
    changeIndex(index) {
      // index 鼠标移上某一个一级分类的元素的索引值
      this.currentIndex = index;
    },
    // 一级分类鼠标移出的事件回调
    leaveIndex(){
      // 鼠标移出currentIndex=-1
      this.currentIndex =-1;
    }
},

4)使用原生JS实现二三级分类的显示与隐藏(利用三元表达式实现)

7. 三级联动的防抖和节流

防抖:前面的触发都取消,最后一次执行在规定时间之后才会触发。也就是说如果连续快速的触发,只会执行最后一次。

节流:在规定间隔时间内,不会重复触发回调,只有大于了时间间隔,才会触发,把频繁触发变为少量触发。

本项目中,鼠标不停的在三级联动上来回切换,进行节流操作,把频繁触发变为少量触发。

这里需要使用 lodash,一般都下载好了的。并且进行按需加载。

//在TypeNav/index.vue中 
//按需引入节流
import throttle from "lodash/throttle";

methods: {
    // 鼠标进入修改响应式数据currentIndex属性
    // throttle回调函数不要用箭头函数,防止出现上下文this问题
    changeIndex: throttle(function (index) {
      // index:鼠标移上某一个一级分类的元素的索引值
      this.currentIndex = index;
    }, 50),
},

 8.三级联动的路由跳转(从home跳转到search)

需求:当点击某个分类时,进行路由跳转,并把分类的名字和id传给search,然后search拿到参数向服务器发请求,显示相应的数据。

路由跳转的两种方式:声明式导航和编程式导航。

如果使用声明式导航,需要使用<router-link></router-link>,并且<router-view>会生成好多组件,会出现页面的卡顿。

如果使用编程式导航,需要给每一个a添加点击事件。

这里使用编程式导航+事件委派。

事件委派:在父节点上添加事件监听器,利用事件冒泡影响每一个子节点。

注意两个问题:

1)事件委派,是把全部的子节点的事件委派给父亲节点,如何确定我们点击的一定是a标签

利用自定义属性,给子节点中的a标签添加自定义属性data-categoryName,其余子节点没有。

2)确定了点击的是a标签,如何区分是一级,二级,三级分类的标签

同样也是利用自定义属性,给子节点中的a标签添加自定义属性data-category1Id、data-category2Id、data-category3Id。

步骤:先判断是不是a标签,是则进一步判断是哪一个分类。

1)先给一级分类的父标签添加点击事件,进行路由跳转。

2)给每一分类级的a标签添加自定义属性。

 3)编写跳转函数

//进行路由跳转
    // 从home跳转到search
    goSearch(event){
      //获取当前事件的触发对象
      let element=event.target;
      //利用节点的dataset属性,获取节点的自定义属性(要小写)
      let { categoryname, category1id, category2id, category3id }=element.dataset;
      //判断,如果categoryname为真,则表示当前点击的是a标签
      if(categoryname){
        //整理路由跳转的参数
        let location={name:'Search'};//记得在router/index.js中给search命名
        // 小写的是自定义属性值,大写的是新添加的属性值
        // 需要获取小写的自定义属性值给大写的新添加的属性值
        let query={categoryName:categoryname};
        // 判断是一级,二级,三级哪一个分类
        if(category1id){
          query.category1Id=category1id;
        }else if(category2id){
          query.category2Id=category2id
        }else {
          query.category3Id=category3id
        }
        //此时query里面就有了name和id
        //再把query给到location
        location.query=query;
        //现在进行传参
        this.$router.push(location)
        
        
      }
    }

9.Search模块中三级联动的显示与隐藏和添加过渡动画效果

步骤:

1)先给TypeNav组件添加一个属性show,表示显示与隐藏三级联动。

2)给三级联动使用v-show,进行显示与隐藏。

3)在搜索页面,最开始三级联动是隐藏的,只有当鼠标移上去,才显示出来。

所以,当组件挂载完毕后,如果不是home组件,就隐藏三级联动

4) 鼠标在全部商品分类上移入移出,进行三级联动的显示与隐藏。

这里可以调用事件委派,给透明封装一个大盒子,在大盒子上进行鼠标移入移出事件。

 5)添加过渡动画

注意:

1)组件或者元素务必要有v-if或者v-show指令

2)记得加一个name,使用transition标签包住

 // 过渡动画的样式
    // 过渡动画开始的状态(进入)
    .sort-enter {
      height: 0px;
    }
    // 过渡动画结束状态(进入)
    .sort-enter-to {
      height: 461px;
    }
    // 定义动画时间、速率
    .sort-enter-active {
      transition: all 0.5s linear;
    }

10.TypeNav组件在进行路由跳转时,会传递参数,就需要发送ajax请求,每一次跳转都会发一次请求,很耗性能,需要进行优化!

操作:最开始的时候,发送请求是在TypeNav组件中的mounted钩子函数中,现在把请求放入到App.vue文件中。因为最先执行的就是App.vue,这样请求就只会发送一次!!!

11.合并参数,实现跳转时的params参数和query参数都可以传递

从首页向Search组件跳转有两种方式:

1.通过搜索关键字跳转(传的是params参数)

2.点击三级导航的链接跳转(传的是query参数)

如果既点击了搜索按钮,又点击了三级导航的链接,那么点击的后者的参数会覆盖前者的参数,所以需要进行参数的合并,这样两个参数都可以传递!!!

//在Header.vue中
methods:{
    //在搜索框输入params参数后,点击搜索按钮进行跳转
    search(){
      // this.$router.push(`/search/${this.keyword}`)
      //这里进行参数合并,query和params
      let location={name:'Search',params:{keyword:this.keyword||undefined}}
      location.query=this.$route.query;
      this.$router.push(location)
    }
}

在TypeNav/index.js中 

12.开发首页的ListContainer(轮播图)、Floor(底部)组件 


 首先使用mock搭建模拟数据

步骤:

1)先安装:npm install mockjs

2)在src文件夹中创建mock文件夹,用来存放json假数据

3)在mock文件夹中准备假数据,引入ListContainer、Floor的数据

4)在public下创建一个images文件夹,把mock数据需要的图片存放进去

5)在mock文件夹下创建mockServe.js,通过Mock.mock方法进行模拟数据

6)在main.js里引入src/mock/mockServe.js,让配置假数据执行一次

7)在api文件夹中创建mockAjax.js文件,模拟发送请求。

里面的内容与原先二次封装的request.js文件中内容一样,但是要注意,记得把基础路径改为'/mock',因为我们是模拟发送请求

8)在src/api/index.js文件中,进行api的统一管理,模拟轮播图的接口


其次,获取轮播图数据

1)在组件挂载完毕后,向服务器发送请求

 2)使用vuex三连环

3)接收数据

 

然后,绘制轮播图 

这里需要使用swiper插件

安装swiper插件:npm i swiper --save

使用swiper的三步骤:

1.引入相应的包

2.页面结构必须先有(给轮播图添加静态效果)

3.有结构后再new Swiper实例(给轮播图添加动态效果)

步骤:

1.引包

1)在main.js中引入css(这样组件都可以使用)

// 引入swiper样式
import 'swiper/css/swiper.css'

2)在listContainer组件中引入swiper

 // 引包
 import Swiper from 'swiper'

2.搭建轮播图页面的结构

3.添加动态效果(重点)

    这里要注意,不能直接在mounted里面写,一般情况下在里面写是正确的。但这里不行,这里有dispatch,涉及到异步语句,需要发请求,拿数据,导致v-for遍历的时候,结构还没有完全,所以还不能实例化swiper。

    如果直接在里面写,会先实例化swiper,再搭建结构,这样是不符合swiper操作步骤的。

    页面结构必须先生成,再new Swiper!!!

解决方法:

1)使用定时器包裹swiper,但是有问题,因为发送ajax请求的时间不确定,所以定时器时间不好把握。

2)使用watch监听,但是只使用watch,只能监听到数据的变化,不能判断v-for已经执行完毕了,所以也不行。

3)使用watch+$nextTick,在监听到数据回来后,结构完成后,使用$nextTick来实例化swiper,就可以完成动态效果渲染。

所以使用方法三。

//在Home/ListContainer.vue
  watch:{
      // 监听banners数据的变化,有空数组变为数组里有4个元素
      banners:{
        immediate:true,
        handler(newValue,oldValue){
          // 通过监听banners属性值的变化,如果执行了Hanler,则表示数据有了,
          //但是只能保证有数据了,不能保证v-for已经执行完毕
          //只有v-for执行完后,才有结构,才能实例化swiper
          //所以这里需要添加$nextTick
          // nextTick:在下次DOM更新, 循环结束之后,执行延迟回调。在 修改数据之后 立即使用这个方法,获取更新后的DOM。
          this.$nextTick(()=>{
            // 下面的是直接复制的swiper里面的代码
            var mySwiper = new Swiper ('.swiper', {
            loop: true, // 循环模式选项
            autoplay:true,//自动切换
            // 如果需要分页器
            pagination: {
            el: '.swiper-pagination',
            clickable:true,
             },
            // 如果需要前进后退按钮
            navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
            },
          })
        })
      }
    }
  }

开发floor组件

和前面一样,先写静态,之后发请求(写api),写完api之后就写仓库三连环,仓库存储数据后,组件捞数据,捞完之后展示。

1)配置api接口

2)仓库三连环存储数据

在store/home.js中写vuex三连环

3)派发action

注意,这里不能在floor组件里面派发,因为这里有两个floor组件,需要使用v-for遍历,所以在他的父组件home组件去派发。

4)收取数据

因为现在这个数据在父组件home里,子组件floor想要得到数据,就得使用组件间的通信,这里使用父向子传。

使用props传递。

5)渲染数据到页面

6)floor轮播图制作

注意在这里就可以直接在mounted里面实例化swiper。

因为这里请求是父组件发的,父组件通过props传递过来,并且结构已经有了,才执行的mounted


封装Carsouel全局组件

因为在ListContainer和Floor中都用到了carsouel轮播图,我们可以封装成一个全局组件,这样方便使用。

封装成为全局组件,注意里面的内容都是一样的,所以需要修改一下原先的内容。

由于floor组件的是父亲传过来的值,所以里面数据已经有了,所以数据没有变化,无法通过watch监听到,所以要使用immediate,立即监听。

由于ListContainer组件的v-for结构还不能确定已经完成了,所以要使用nextTick

然后两者一结合,写在components文件夹里面创建的一个Carousel文件夹中。

这样当需要使用轮播图的时候,直接引入这个文件就可以了。

注意:全局组件记得在main.js中引入并注册!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值