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

Posted ForMyself.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了电商前台项目:完成Home首页模块业务相关的知识,希望对你有一定的参考价值。

Vue2项目前台开发:第二章

一、项目开发的步骤

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

经分析,Home首页可以拆分为7个组件,分别是:

二、Home首页拆分静态组件

1.完成TypeNav 三级联动组件:全局组件

三级联动(导航部分)Home,Search,Detail组件都在使用,可以把它注册为全局组件,全局组件一般都创建在components里,这里放错了

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

2.完成其余静态组件:局部组件

1、创建组件,组件文件夹 => index.vue
2、导入结构(html) 样式(css) ,查看图片位置有无错误进行修改(最好每个组件文件夹内都新建一个images文件夹,然后把相应的图片拿过来)
3、引入组件 => 注册组件 => 使用组件

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

1.axios二次封装

向服务器发请求的方式有:XMLHttpRequest,fetch,JQ,axios

这里用axios,安装:脚手架目录下 npm i axios

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

2、在项目当中经常会出现 api 文件夹,一般是放关于【axios】请求的
baseURL:'/api',:基础路径,发请求的时候,路径当中会出现基础api
timeout:5000,: 代表请求超时的时间5s,在5s之内没有响应就失败了

3、axios基础不好,可以参考 git | axios 文档,后边要补一下axios的内容

//src/api/request.js
//本文件是对axios的二次封装
import axios from 'axios';

//1.利用axios对象的方法create,创建一个axios实例
const requests = axios.create(
    //配置对象
    baseURL: '/api',  //基础路径,发请求时路径中的api
    timeout: 5000  //代表请求超时的时间为5s
);

//2.请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => 
    //config:配置对象,对象里面有一个属性很重要,headers请求头
    return config;
);

//3.响应拦截器
requests.interceptors.response.use(
    (res) => 
        //成功的回调函数,服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
        return res.data;
    ,
    (error) => 
        //响应失败的回调函数
        return Promise.reject(new Error('faile'));
    );

export default requests;

2.api接口统一管理

项目很小:完全可以在组件的生命周期函数中发请求
项目大,有很多接口:axios.get(‘xxx’)

// src/api/index.js
//本文件用于:API的统一管理
import requests from './request';

//三级联动(导航部分)的接口
// /api/product/getBaseCategoryList get 无参数
export const reqCategoryList = function () 
    //发请求:axios发请求返回结果是Promise对象
    return requests(
        url: '/product/getBaseCategoryList',
        method: 'get'
    );

可以去main.js里测试是否能发送ajax请求

import  reqCategoryList  from './api';
reqCategoryList();

1、跨域问题

什么是跨域:协议,域名,端口号不同的请求,称之为跨域

从这里http://localhost:8081/#/home ----前端项目本地服务器
向这里发请求 http://gmall-h5-api.atguigu.cn ---- 后台服务器

2、跨域的解决方案:JSONP,CROS,配置代理
具体配置代理怎么搞详见:脚手架配置代理

3.nprogress进度条的使用

安装nprogress插件 npm i nprogress

只要项目当中发请求,进度条就开始往前动,服务器数据返回之后,进度条就结束

用在 请求和响应拦截器中 src/api/request.js

nprogress.start方法:进度条开始
nprogress.done方法:进度条结束

四、Vuex模块化开发

vuex是官方提供的一个插件,状态管理库,集中式管理项目中组件共用的数据。

切记,并不是全部项目都需要vuex
如果项目很小,完全不需要vuex
如果项目很大,组件很多,数据很多,数据维护很费劲,需要vuex

安装vuex npm i vuex@3,详情去看Vuex笔记

1、本项目采用Vuex模块化开发,每个模块建立自己的小仓库,然后小仓库引入到大仓库里并放到Vuex实例身上(Vuex.Store)

2、去main.js里引入大仓库,并把$store放到每个组件实例身上

五、TypeNav导航三级联动

TypeNav是全局注册组件,一般都放在components文件夹中

1.三级联动展示数据

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

(2)去home仓库请求数据

1、actions执行的时候,要通过api里面的接口函数调用,向服务器发请求,获取服务器的数据,需要把之前的api引入进来,在这里发请求就是要调用这个reqCategoryList函数,如果请求成功(code===200),那么把数据交给mutations进行处理
2、mutations中把数据给state
3、state中覆盖掉初始值,注意要根据接口的返回值来初始化,服务器返回对象,初始值就是对象,服务器返回数组,初始值就是数组。这里因为后台数据响应体是数组,故初始值为一个空数组

(3)TypeNav接收数据

写法1:使用mapState来搞个计算属性,使用对象形式,这里和之前学的不一样的地方是,属性值写成一个函数,参数是大仓库的state,可以顺着找到home的state。这样的话我们就拿到了home里请求到的数据,可以直接使用插值语法在页面使用了


写法2:当然啊,这里还有另一种写法,那就是首先小仓库home开启命名空间namespaced:true


然后dispatch时就要变成模块名/actions方法名,计算属性就变成数组:

(4)把数据渲染到页面上

观察后台数据的结构,大概是这样子的:

[
    //一级数据
    
       [
        //二级数据
        
            [ 三级数据id,name,,],
            id,
            name
        ,
        ,
        
       ],
       id,
       name 
    ,
    ,
    
]

数组里有好多对象(一级数据),对象里有数组,数组里还有对象(二级数据),对象里还有数组,数组里还有对象(三级数据)

一级数据是大的表单,

2.一级分类动态添加背景颜色

(1)采用css样式实现

so easy,但是没有挑战性,我们来搞点难的

.item:hover
	background:skyblue;

(2)通过JS实现

给一级分类添加鼠标经过事件和鼠标离开事件,鼠标离开老师搞了个事件委托,我觉得没必要啊,把鼠标离开放到大div上就行吧,这样只要鼠标在二级和三级数据上,一级数据就会保持高亮。

1、先设置一个响应式属性,存储用户鼠标移上哪一个一级分类currentIndex = -1 ;代表鼠标谁都没有移上去。

  <div class="item bo" 
      v-for="(c1,index) in categoryList" 
       :key="c1.categoryId"
       @mouseleave="leaveIndex">
           <h3 @mouseenter="changeIndex(index)" 
           :class="cur: currentIndex === index">
               <a href="">c1.categoryName</a>
           </h3>
           ......
  </div>

2、然后鼠标移上去时触发回调,拿到当前index给currentIndex,这样的话添加的:class="cur: currentIndex === index就会变成true,从而cur样式生效(css去写个背景色)

 data() 
    return 
      // 响应式属性,存储用户鼠标移上哪一个一级分类
      currentIndex: -1, // 代表鼠标谁都没有移上去
    ;
  ,
  methods: 
    // 鼠标进入修改响应式数据currentIndex属性
    changeIndex(index) 
      // index 鼠标移上某一个一级分类的元素的索引值
      this.currentIndex = index;
    ,
    // 一级分类鼠标移出的事件回调
    leaveIndex()
      // 鼠标移出currentIndex=-1
      this.currentIndex =-1;
    
  ,

3、鼠标离开后currentIndex置为-1,就不会触发样式cur

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

先把原来的css删掉(display:none和hover display:block)
然后用原生JS实现可以,用v-show实现也可以

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

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

(1)防抖和节流是什么

防抖:前面的所有的触发都被取消,最后一次执行在规定的事件之后才会触发,也就是说如果连续的快速触发,只会执行一次 ----------------------当事件被触发后,延迟 n 秒后再执行回调,返回的是一个函数

const result = _.debounce(function()
    
,1000)

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

const result = _.throttle(function()
    
,1000)

防抖(回城):用户操作频繁,无关规定时间长短,期间只执行一次。
节流(平a):用户操作很频繁,但是把频繁的操作变成少量操作【可以给浏览器充裕的时间解析代码】即规定时间执行一次。

(2)三级联动导航节流

鼠标来回滑动的时候,把频繁触发变成少量触发,进行节流

// 这种引入的方式,是把lodash全部功能函数引入,使用时_.throttle
import _ from 'lodash';
// 最好的引入方式:按需加载
import throttle from 'lodash/throttle'
...

  methods:
	  // 鼠标进入修改响应式数据currentIndex属性
	  //这里不能写简写形式,返回的结果就是一个函数嘛
	  changeIndex:throttle(function(index)
	    // index 鼠标移上某一个一级分类的元素的索引值
	     this.currentIndex = index;
	  ,50),
  

这里的throttle回调函数别用箭头函数,可能出现上下文this问题

5.三级联动路由跳转与传参(目标search)

这里要用到自定义属性,忘了去翻:js自定义属性笔记

(1)需求分析

实现:当你点击某个分类(a链接)的时候,会从home模块跳转到search模块,并且把分类的名字categoryName和ID传递给search模块,然后search模块拿到这些参数向服务器发请求展示相应数据

路由跳转可以用<router-link></router-link>,但是这样的话<router-view>会生成好多组件,页面会卡(这块儿不太懂为啥route-rlink是组件)

如果只用编程式导航,要给每个a加点击事件,也不太行

所以最好的解决方案是编程式导航+事件委派

(2)编程式导航+事件委派

事件委派可以避免给每个a去添加点击事件,方法是在包含所有a标签的父标签里(一级数据的父标签即可)添加点击事件,这样点里边的任意标签都会事件冒泡到父标签,触发点击事件


但是这里也存在一些的问题:
1、事件委派,是把全部的子节点【h3,dt,dl,em,a】的事件委派给父亲节点
2.、只有点击a标签的时候,才会进行路由跳转
我们怎么设置只有点击到a标签的时候才进行路由跳转呢?

解决方案:自定义属性
给所有a标签添加自定义属性data-categoryname,然后使用事件对象event拿到当前点击对象event.targetevent.target.dataset,返回的是该元素身上的所有自定义属性,并使用解构赋值来接收,如果categoryname这个属性不为空,那么就说明点击的是a标签

3、如何获取参数【1,2,3级分类的产品的名字和ID】?
名字好说,解构赋值都已经拿到了,主要是id怎么搞?

解决方案:还是自定义属性,分别给每一级别数据的a标签添加自定义属性


使用解构赋值接收,然后做个判断,如果拿到一级数据的id,就传一级数据,二级传二级,以此类推,最后写出来的点击事件函数长这样:

goSearch(event) 
    //拿到当前点击对象的所有自定义属性,使用解构赋值接收
     let  categoryname, category1id, category2id, category3id,  = event.target.dataset;
     //判断,如果当前点击对象有categoryname这个自定义属性,就说明是a标签(因为没有肯定返回undefined)

     if (categoryname)   //如果是a标签,就跳转并传参
         //1.首先定义一个query参数对象,先把categoryname拿过来
         let querydj =  categoryName: categoryname ;
         //2.判断,如果收到了一级数据的id,就给querydj添加属性和值,以此类推
         if (category1id) 
             querydj.category1Id = category1id; //添加属性
          else if (category2id) 
             querydj.category2Id = category2id; //添加属性
          else 
             querydj.category3Id = category3id; //添加属性
         
         //这样querydj拿到了类别名字和id,就可以传参了
         this.$router.push(
             name: 'sousuo',
             query: querydj   //把上面定义的那玩意儿拿过来
         );
     ;

以上是关于电商前台项目:完成Home首页模块业务的主要内容,如果未能解决你的问题,请参考以下文章

47.4K+Star的电商开源项目|附超详细的文档

案例:基于SSM的bbs论坛

一些开源项目

github 31.6K star的Springboot开源电商系统,值得关注

电商前台项目:完成加入购物车功能和购物车页面

分布式电商系统项目总结