Vue2电商前台项目(二):完成Home首页模块业务

一、项目开发的步骤

1、书写静态页面(HTML,CSS)
2、拆分组件
3、获取服务器的数据动态展示
4、完成相应的动态业务逻辑

经过分析之后,Home首页可以拆分为7个组件:TypeNav三级联动导航,ListContainer,Recommend,Rank,Like,Floor,Brand。主要得看你静态页面把谁谁写在一个结构里面了,组件就得在一个里面。

二、Home首页拆分静态组件

1.TypeNav三级联动的完成

如果有哪个组件在项目中频繁使用(三级联动在Home、Search、Detail都用到了),就把它注册成全局组件。

好处:只需要注册一次可以在项目的任意地方使用。

首先在home下新建一个三级联动组件的文件夹TypeNav,底下有一个文件叫index.vue,然后把它注册为全局组件,回到入口文件main.js,需要使用到Vue.component

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

现在回到home组件里就可以使用TypeNav了:

<!-- 三级联动全局组件 ,它已经注册为全局组件了,不需要再引入-->
    <TypeNav/>

2.完成其余静态组件

完成轮播图和右边快报的部分

拆分组件就三步:结构、样式、图片资源

3.POSTMAN测试接口

刚刚经过postman工具测试,接口是没有问题的
如果服务器返回的数据code字段200,代表服务器返回数据成功
整个项目,接口前缀都有/api字样

三、请求服务器数据的准备工作

1.axios二次封装

向服务器发请求:XMLHttpRequest、fetch、JQ、axios

为什么需要进行二次封装axios?
请求拦截器、响应拦截器:请求拦截器,可以在发请求之前可以处理一些业务、响应拦截器,当服务器数据返回以后,可以处理一些事情

首先安装axios :npm install axios

项目当中通常放API文件夹用于放axios,src/api/request.js:

//对于axios进行二次封装
import axios from 'axios'

//利用axios对象的方法create,去创建一个axios实例
//request就是axios,只不过配置一下

const requests = axios.create({
    //配置对象
    //基础路径
    //baseURL: '/api',
    //代表请求时间超时,超过五秒还没发回来说明请求失败
    timeout: 5000,
})
//create方法里面可以写对象

//请求拦截器
requests.interceptors.request.use((config) => {
    //config是一个配置对象,里面有一个属性很重要:header请求头
    return config
})

//响应拦截器,有成功回调和失败回调
requests.interceptors.response.use((res)=>{
//成功的回调函数:服务器相应数据回来以后,响应拦截器可以检测到
return res.data
},(err)=>{
//响应失败
return Promise.reject(new Error('false'))
})
export default requests

2.api接口统一管理

项目很小:完全可以在组件的生命周期函数中发请求,在mounted或者created里发请求,存储在data当中。

项目大的话,专门建立一个index.js进行统一管理

//当前这个模块,所有API接口进行统一的管理
//发请求用到axios,引入进来
import requests from "./request";

//三级联动的接口
 export const reqcategoryList=()=>{
    //axios发请求返回promise对象
    return requests({url:'http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList',method:'get'})
 }

main.js调用

import {reqcategoryList} from '@/api'
reqcategoryList()

但是请求错误,因为出现了跨域问题,我们所在的是本地服务器,请求的接口不在

解决跨域问题:JSONP、CROS、代理

这里我们选择代理,在vue.config.js:

//代理跨域,第三方
  devServer: {
    proxy: {
      '/api': {
        target: 'http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList',
        //pathRewrite: { '^/api': '' },
      },
    },
  }

注意:数据请求需要服务器+接口 不要只是访问服务器这样是拿不到数据的,
比如 http://gmall-h5-api.atguigu.cn(这是服务器) /api/product/getBaseCategoryList(这是接口)把接口放在服务器后面就可以
例如:http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList 不要只是访问服务器

3.nprogress进度条的使用

安装插件:npm install nprogress

start:进度条开始

done:进度条结束

//引入进度条
import nprogress from 'nprogress'
//引入进度条的样式
import 'nprogress/nprogress.css'
//请求拦截器
requests.interceptors.request.use((config) => {
    //进度条开始动
    nprogress.start()
    //config是一个配置对象,里面有一个属性很重要:header请求头
    return config
})

//响应拦截器,有成功回调和失败回调
requests.interceptors.response.use((res) => {
    //进度条结束
    nprogress.done()
    //成功的回调函数:服务器相应数据回来以后,响应拦截器可以检测到
    return res.data
}, (err) => {
    //响应失败
    //return Promise.reject(new Error('false'))
    return err.message
})
export default requests

四、Vuex模块化开发

vuex是官方提供一个插件,状态管理库,集中式管理项目中组件共用的数据。
切记,并不是全部项目都需要Vuex,如果项目很小,完全不需要Vuex,如果项目很大,组件很多、数据很多,数据维护很费劲,Vuex几个核心概念:

state:仓库存储数据的地方
mutations:唯一修改state手段
actions:处理action,可以书写自己的业务逻辑,也可以处理异步
getters:计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
modules:模块式开发

安装vuex:npm i vuex@3

注意vue2的一定不要下错!!!!!

vuex是一个对象,store是它的一个方法,而这个方法是一个构造函数,可以初始化vue仓库

新建一个src下的store文件/index.js:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

//对外暴露store类的一个实例
export default new Vuex.Store({
    state:{},
    mutations:{},
    actions:{},
    getters:{}
})

然后到入口文件去注册一下:

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

new Vue({
  render: h => h(App),
  router,
  //注册仓库:组件实例的身上会多一个$store的属性
  store
  //KV一致省略V
  //注册路由信息:当这里书写router的时候,组件身上都拥有$route,$router
}).$mount('#app')

如果项目过大,数据过多,可以让vuex实现模块式开发,大仓库拆分成小仓库,每一个小仓库存储相应模块的数据

比如我们现在创建home、search的小仓库,分别在store下创建两个文件夹为home、search

然后他俩下面再创建index.js

//search模块下的小仓库
const state={}
const mutations={}
const actions={}
const getters={}
export default {
    state,
    mutations,
    actions,
    getters
}

然后把两个小仓库合并到大仓库中去

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

历尽千辛万苦终于知道为啥我没有vuex的数据了,下载的时候下成了最新版的vuex,得先卸载了最新的再下,卸载:npm uninstall vuex

五、TypeNav导航三级联动

1.三级联动展示数据

一个小更改,之前的三级联动我们写在了home下,以后像这种不会更改的组件都写在components里

(1)组件挂载完毕后dispatch给Vuex

//组件挂载完毕,可以向服务器发请求
  mounted(){
    this.$store.dispatch('categoryList')
  },

(2)去home仓库请求数据

code号为200时,就把数据给过去

import { reqcategoryList } from "@/api"
//home模块下的小仓库
const state = {
    //state中数据默认初始值别瞎写,服务器返回的是对象,服务器返回数组【根据接口返回初始化】
    categoryList:[]
}
const mutations = {
    CATEGORYLIST(state,categoryList){
        state.categoryList=categoryList
    }
}
const actions = {
    //通过api里面的接口函数调用,向服务器发请求,获取服务器的数据
    async categoryList({ commit }) {
        let result = await reqcategoryList();
        if (result.code == 200) {
            commit("CATEGORYLIST", result.data)
        }
    }
};

(3)TypeNav接收数据

import{mapState} from 'vuex'
、、、
computed:{
    ...mapState({
      //右侧需要的是一个函数,当使用这个计算属性的时候,右侧函数会立即执行一次
      //注入一个参数state,其实即为大仓库中的数据
      categoryList:(state)=>{
        return state.home.categoryList
      }
    })
  }

(4)v-for去掉多余a标签

一级分类叫item,二级分类叫subitem,是一级分类中的categoryChild,还有三级分类,用em做的

<div class="item" v-for="c1 in categoryList" :key="c1.categoryId">
            <h3>
              <a href="">{{c1.categoryName}}</a>
            </h3>
            <div class="item-list clearfix">
              <div class="subitem" v-for="c2 in c1.categoryChild" :key="c2.categoryId">
                <dl class="fore">
                  <dt>
                    <a href="">{{c2.categoryName}}</a>
                  </dt>
                  <dd>
                    <em v-for="c3 in c2.categoryChild" :key="c3.categoryId">
                      <a href="">{{c3.categoryName}}</a>
                    </em>
                  </dd>
                </dl>
              </div>
            </div>
          </div>

2.一级分类动态展示背景颜色

(1)采用样式完成(hover)

         .item:hover{
                      background-color: skyblue;
                    }

(2)通过js完成

当用户鼠标移到哪个一级分类上就把它的索引值index给存起来,mouseenter事件,传参过来index,设置一个动态类名,谁被移上去谁就有那个类名

<div class="item" v-for="(c1,index) in categoryList" :key="c1.categoryId" :class="{cur:currentIndex==index}">
            <h3 @mouseenter="changeIndex(index)">
              <a href="">{{c1.categoryName}}</a>
            </h3>
data(){
    return {
      currentIndex:-1
      //用来记录鼠标在谁上,-1表示都不在
    }
  },
methods: {
    //鼠标进入修改index
    changeIndex(index){
      //index是鼠标在的一级分类
      this.currentIndex=index
    }
  },
.cur{
      background-color: skyblue;
     }

这样写实现了鼠标移上去背景颜色变蓝,但是鼠标移下来它还是蓝的(在鼠标最后待的h3)

所以还得有mouseleave事件,本来我还想着动颜色,结果发现直接index=-1更简单

<h3 @mouseenter="changeIndex(index)" @mouseleave="leaveIndex(index)">
、、、
leaveIndex(index){
      //鼠标移出的index=-1
      this.currentIndex=-1
    }

最后老师又更改了一下,当鼠标从第一个h3移到h2的时候蓝色不变,移出h2蓝色才消失,那么这个时候事件不能添加给h3了,用到了事件的委托,移出事件添加给父标签

<div @mouseleave="leaveIndex">
        <h2 class="all">全部商品分类</h2>
        <div class="sort">
          、、、、
              <h3 @mouseenter="changeIndex(index)">
                <a href="">{{ c1.categoryName }}</a>
              </h3>
              、、、

3.JS控制二、三级数据显示和隐藏

最开始是通过css样式display:none、block实现的

js实现:谁有背景颜色谁就有二三级分类

<!-- 二、三级分类 -->
<div class="item-list clearfix" :style="{display:currentIndex==index?'block':'none'}">

4.三级联动的防抖与节流

(1)防抖和节流是什么(面试频率高

卡顿现象:事件触发非常频繁,而且每一次的触发,回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿)

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

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

防抖:写一个简单的页面来模拟,用户在搜索input表框时,直至输入停止再过一秒之后ajax才会发请求。(强调时刻)

//防抖:前面的所有的触发都被取消,最后一次执行 在规定的时间之后才会触发,也就是说如果连续快速的触发 只会执行一次
let input = document.querySelector('input');
//文本发生变化立即执行
input.oninput=_.debounce(function(){
console.log('ajax发请求')
},1000);
//lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟器】
//1:1odash函数库对外暴露_函数

lodash原生代码 得看

节流:多么频繁的点击都是五秒钟加一次(强调时间)

//计数器:在一秒以内,数字只能加上1
button.onclick =_.throttle(function(){
//节流:目前这个回调函数5S执行一次,
//加入这里面有很多的业务代码,是不是可以给浏览器很充裕的时间去解析
count++;
span.innerHTML = count
console.log('执行')
},5000);
//防抖:用户操作很频繁,但是只是执行一次
//节流:用户操作很频繁,但是把频繁的操作变为少量操作【可以给浏览器有充裕的时间解析代码】

(2)三级联动导航节流

在项目中使用一下节流技术,防止用户操作过快

项目中node_module里有lodash,不用再自己下载

//这种是把lodash全部功能引入过来了
//import _ from 'lodash'
//按需引入,默认暴露所以不用再加{}了
import throttle from 'lodash/throttle'
、、、
methods: {
    //鼠标进入修改index
    // changeIndex(index) {
    //   //index是鼠标在的一级分类
    //   this.currentIndex = index;
    // },
    changeIndex:throttle(function(index){
      this.currentIndex = index;
    },50),

注意throttle回调函数不要使用箭头函数,容易产生this指向问题

明天继续更

上一篇:C++ List 到 Python List 的转换


下一篇:SQL语句学习+牛客基础39SQL