Vue3.2 电商前台项目(三)—— Home页面和Search页面(axios的封装、分页器的封装)

码云仓库地址

一、 Home组件

开发流程

  • 拆分静态组件 | 页面
  • 配置 api 请求
  • vuex 配置
  • 组件获取数据,动态展示数据

1. 全局组件:三级联动组件的实现

  • 三级联动组件在多个位置(home、search、detail)使用到了,所以将其注册为全局组件(只需要注册一次,就可以在任意需要的地方使用)
  1. 新建 src / components / TypeNav / index.vue
  2. main.js 中进行全局注册
    全局注册时接收两个参数:第一个参数为全局组件的名字,后续使用用到的就是这个名字;第二个参数为要注册的组价
// main.js

// 导入三级联动组件
import TypeNav from '@/components/TypeNav'
createApp(App)
  .component('type-nav', TypeNav) // 全局注册三级联动组件
  .mount('#app')
  1. 使用
    src / view / Home / index.vue
<!-- 三级联动组件 -->
    <type-nav></type-nav>

2. 首页局部组件

  1. 创建需要的局部组件
  2. 在 views / Home /indec.vue 中引入和使用
<template>
  <div>
    <!-- 三级联动组件 -->
    <type-nav></type-nav>
    <!-- 列表组件 -->
    <list-con></list-con>
    <!-- 今日推荐组件 -->
    <today-recommend></today-recommend>
    <!-- 商品排行组件 -->
    <rank></rank>
    <!-- 猜你喜欢组件 -->
    <like></like>
    <!-- 楼层 -->
    <floor></floor>
    <!-- 楼层 -->
    <floor></floor>
    <!-- 商标组件 -->
    <brand></brand>
  </div>
</template>

<script setup>
import ListCon from './ListContainer'
import todayRecommend from './TodayRecommend'
import rank from './Rank'
import like from './Like'
import floor from './Floor'
import brand from './Brand'
import {
     } from 'vue'
</script>
<style lang="scss" scoped></style>

3. 接口工具:postman

postman下载链接

  • 本项目中:服务器返回code为200,代表请求成功
  • 整个项目的接口前缀为 /api

4. axios 的二次封装

目的:基于axios封装一个请求工具,调用接口时使用。封装请求拦截器、响应拦截器,进行一些业务处理
在后续需要调用接口时,要引入该工具

  1. 安装 axios
cnpm install --save axios
  1. 新建 src / api / request.js
    api 文件夹,用于存放axios相关的
    request.js 用于二次封装axios
/** *****************axios的二次封装,主要是封装请求拦截器和响应拦截器 ************/
/** 实现步骤
 * 1. 创建一个新的axios实例
 * 2. 请求拦截器,如果有token进行头部携带
 * 3. 响应拦截器
 **/

// 导入axios
import axios from 'axios'

/**
 * TODO-1: 利用axios的create方法,创建一个新的axios实例
 */
const instance = axios.create({
   
  // axios的配置
  // baseUrl:基础路径,基于哪个路径
  //  如本项目中接口前缀为 /api,设置baseURL的作用就是后续见到访问地址时,会自动加上 /api ,避免每次都去书写
  baseURL: '/api',
  // 请求超时的时间,在5秒内无响应则请求失效
  timeout: 5000
})

/**
 * TODO-2:请求拦截器
 * 在发请求之前,请求拦截器可以进行监测,以便在请求发出前进行一些处理
 */
instance.interceptors.request.use(config => {
   
  // config:配置对象,其中含请求头header属性
  return config
})

/**
 * TODO-3:响应拦截器
 */
instance.interceptors.response.use(response => {
   
  // 响应成功的回调
  // 请求成功返回data,后续可直接使用data
  return response.data
}, err => {
   
  // 响应失败的回调
  // 终止Promise
  return Promise.reject(err)
})

// 对外暴露,外部才可以使用
export default instance

5. API 接口统一管理

  • 项目很少,比如只有几个接口,可以直接在组件生命周期中发送请求
  • 大项目(比如组件上百,接口几十的情况下),可以对接口统一进行管理,这样方便修改
  1. 新建 src / api / index.js 用于接口的统一管理
/** *************** 接口的统一管理 *******************/

// 导入封装好的axios
import requests from './request'

/**
 * 三级联动接口
 */
export const reqCategoryList = () => requests({
   
  url: '/product/getBaseCategoryList',
  method: 'get'
})

5.1 配置代理,解决跨域问题

module.exports = {
   
  // 代理跨域
  devServer: {
   
    proxy: {
   
      '/api': {
   
        target: 'http://39.98.123.211' // 服务器地址
        // pathRewrite: { '^/api': '' },
      }
    }
  }
}

6. vuex 模块式开发

  • vuex 是vue官方提供的插件,用于集中式状态管理,管理项目中公用的数据
  1. 新建 src / store / index.js
    如果安装的时候选择了vuex,则该文件会自动创建并在main.js中注册
import {
    createStore } from 'vuex'

// state:仓库存储数据的地方
const state = {
   }
// mutations:修改state的唯一手段
const mutations = {
   }
// actions:处理action,可以处理异步和书写业务逻辑
const actions = {
   }
// getters:仓库的计算属性,用于简化仓库数据
const getters = {
   }
export default createStore({
   
  state,
  mutations,
  actions,
  getters
})

  • 当项目过大,模块多,接口多,可以使用vuex的模块化管理
  • 让代码更好维护,让多种数据分类更加明确
  • 每个组件的state、actions、mutations、getters单独管理,最后引入
  1. 在store目录下建立需要使用vuex的组件文件夹,如:home/index.js、search/index.js,分别管理需要的vuex内容
    在这里插入图片描述
const state = {
   
   ...
}
const mutations = {
   
   ...
}
// getters:计算属性,项目中主要用于简化仓库中的数据
const getters = {
   
    ...
}
const actions = {
   
   ...
}

export default {
   
    state,
    mutations,
    getters,
    actions
}
  1. store/index.js中引入
import {
    createStore } from 'vuex'

import home from './home'
import search from './search'
export default createStore({
   
// 实现vuex仓库模块式开发存储数据
  modules: {
   
    home,
    search
  }
})
  • 开发者工具中查看
    在这里插入图片描述

7. TypeNav 三级联动组件

7. 1 三级联动组件的接口请求

  1. Home / index.vue 中,组件挂载完毕就向服务发请求获取三级联动列表
import {
    onMounted } from 'vue'
import {
    useStore } from 'vuex'
// 引入vuex的实例store
const store = useStore()
onMounted(() => {
   
  // 组件挂载完毕后,向服务发请求获取三级联动列表
  store.dispatch('getCategoryList')
})
  1. store / home / index.js 配置
// 导入三级联动的接口函数
import {
    reqCategoryList } from '@/api/index'
const state = {
   
  // state中的初始值要和服务器返回的类型保持一致
  categoryList: []
}
const mutations = {
   
  CATEGORYLIST(state, categoryList) {
   
    state.categoryList = categoryList
  }
}
const getters = {
   
}
const actions = {
   
  // 首页派发的‘getCategoryList’事件
  async getCategoryList({
     commit }) {
   
    // 发送请求
    const result = await reqCategoryList()
    if (result.code === 200) {
   
    //  请求成功,派发一个mutation,并将返回的数据传递过去
      commit('CATEGORYLIST', result.data)
    }
  }
}

export default {
   
  state,
  mutations,
  getters,
  actions
}
  1. Home / index.vue 中使用
// 获取请求到的三级联动列表
const categoryList = store.state.home.categoryList

7.2 通过JS给三级联动设置背景色(事件委托)

  • 方式1: 直接修改css,添加一个hover时的背景颜色
 &:hover {
   
            background-color: skyblue;
          }
  • 通过JS设置 ,在 components / TypeNav / index.vue 中实现
<template>
...
<div class="item" :class="{ active: currentIndex === index }">
	<h3 @mouseenter="changeIndex(index)" @mouseleave="leaveIndex">
   		...
 	</h3>
 </div>
 ...
</template>
<script>
import {
      ref } from 'vue'
// 背景色的处理
// 存储鼠标移入的那一个分类的index
const currentIndex = ref(-1)
// 鼠标移入修改 currentIndex
const changeIndex = (index) => {
     
  currentIndex.value = index
}
// 鼠标移除,重置currentIndex
const leaveIndex = () => {
     
  currentIndex.value = -1
}
</script>
<style lang="scss" scoped>
.item {
     
     &.active {
     
       background-color: skyblue;
    }
}
</style>
  • 希望实现的效果:鼠标先在 “图书、音像、电子书” 分类然后移到 “全部商品分类” 时背景色仍然存在,可以通过 事件委托 实现
    在这里插入图片描述
  • 事件委托 || 事件委派:将本来是子元素的事情委派给父元素来处理
  • 此处将三级联动列表和全部商品分类外层包裹一个 div ,将鼠标移除事件交给这个 div
<!-- 事件委托/事件委派 -->
<div @mouseleave="leaveIndex">
        <h2 class="all">全部商品分类</h2>
        <div class="sort">
          <div class="all-sort-list2">
            <div
              class="item"
              v-for="(categoryItem, index) in categoryList"
              :key="categoryItem.categoryId"
              :class="{ active: currentIndex === index }"
            >
              <h3 @mouseenter="changeIndex(index)">
                <a href="">{
  { categoryItem.categoryName }}</a>
              </h3>
              <div class="item-list clearfix">
                <div
                  class="subitem"
                  v-for="subItem of categoryItem.categoryChild"
                  :key="subItem.categoryId"
                >
                  <dl class="fore">
                    <dt>
                      <a href="">{
  { subItem.categoryName }}</a>
                    </dt>
                    <dd>
                      <em
                        v-for="childItem of subItem.categoryChild"
                        :key="childItem.categoryId"
                      >
                        <a href="">{
  { childItem.categoryName }}</a>
                      </em>
                    </dd>
                  </dl>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

7.3 性能优化:函数防抖与函数节流

  • 当短时间内频繁调用函数时(多次触发事件),浏览器会出现卡顿现象
  • 函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段
  • 函数节流:在规定事件间隔范围内不会触发触发回调,只有大于该时间才会触发,这样把频繁触发变成了少量触发。即:用户操作很频繁,但会把频繁的操作变为少量的操作
  • 函数防抖:取消掉之前所有的触发,最后一次执行在规定时间后才会触发,即连续触发多次只会执行一次,即: 用户操作很频繁,但只执行一次
  • 函数防抖的应用场景:最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。
  • 函数防抖在搜索表单也常见,在用户输入完毕后才发送请求
  • 函数节流应用场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件
7.3.1 lodash 插件
  • lodash 插件内部已经封装好了函数节流与防抖的业务
  1. 安装
    :先搜索项目node_modules中是否含lodash,如果已经自带则不需要安装

cnpm i --save lodash

  1. 使用
    三级联动在频繁切换目录的时候会用到节流,将频繁的操作变为少量的操作
// 按需引入节流
import throttle from 'lodash/throttle'
// 函数节流
const changeIndex = throttle((index) => {
   
  currentIndex.value = index
}, 300)

7.4 三级联动组件的路由跳转和传参

  • 通过编程式导航实现,避免声明式导航出现卡顿的现象;
  • 利用事件委托࿰
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值