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

news/2024/5/8 12:46:17/文章来源:https://blog.csdn.net/weixin_56498069/article/details/132791263

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

Vue基础知识点击此处——Vue.js

文章目录

  • Vue2电商前台项目——完成Home首页模块业务
    • 一、项目开发的步骤
    • 二、Home首页拆分静态组件
      • 1、完成TypeNav三级联动组件:全局组件
      • 2、完成其余静态组件:局部组件
    • 三、请求服务器数据的准备工作
      • 1、axios二次封装
      • 2、api接口统一管理
      • 3、nprogress进度条的使用
    • 四、Vuex模块化开发
    • 五、TypeNav导航三级联动
      • 1、三级联动展示数据
        • (1)组件挂载完毕后dispatch给Vuex
        • (2)去home仓库请求数据
        • (3)TypeNav接收数据
        • (4)把数据渲染到页面上
      • 2、一级分类动态添加背景颜色
        • (1)采用css样式实现
        • (2)通过JS实现
      • 3、JS控制二三级数据显示和隐藏
      • 4、三级联动的防抖和节流
        • (1)什么是防抖
        • (2)什么是节流
        • (3)三级联动节流
      • 5、三级联动路由跳转与传参
        • (1)需求分析
        • (2)编程式导航+事件委派
      • 6、Search模块中三级联动的显示与隐藏
        • (1)实现显示与隐藏效果
        • (2)添加过渡动画
      • 7、解决三级导航ajax请求重复发送的bug
      • 8、合并params与query参数
    • 六、开发Home首页中的ListContainer、Floor组件
      • 1、mock搭建模拟数据
      • 2、mock虚拟数据的ajax请求
      • 3、获取Banner轮播图的数据
      • 4、制作ListContainer轮播图
        • (1)引入相应的包(js和css)
        • (2)搭建轮播图页面结构
        • (3)给轮播图添加动态效果
      • 5、开发floor组件
        • (1)从mock拿数据
        • (2)Home中的数据传给Floor
        • (3)数据渲染到Floor页面
        • (4)把轮播图封装为全局组件

一、项目开发的步骤

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

经分析,Home首页可以拆分为7个组件,分别是:TypeNav三级联动导航,ListContainer(列表),Recommend(推荐),Rank(商品排行),Like(猜你喜欢),Floor(楼层),Brand(商标)

二、Home首页拆分静态组件

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

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

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

请添加图片描述

注意:全局组件要在main.js里面注册,注册为全局组件后使用时不用再注册及引入组件

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

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

请添加图片描述

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

1、axios二次封装

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

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

  • 为什么需要二次封装axios?

    因为要用到 请求和响应拦截器。

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

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

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

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

//src/api/request.js
//对axios进行二次封装
import axios from "axios";//1、利用axios对象的方法create,去创建一个axios实例
//2、request就是axios,只不过配置了一下
const request = axios.create({//配置对象//基础路径:发请求时,路径中会出现基础apibaseURL: "/api",//代表请求超时的时间为5stimeout: 5000,
});// 请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => {//config:配置对象,对象里面有一个属性很重要,headers请求头return config;
});// 响应拦截器
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();

这里会出现跨域问题

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

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

跨域的解决方案:JSONP,CROS,配置代理等

具体配置代理怎么搞详见:脚手架配置代理

请添加图片描述

3、nprogress进度条的使用

安装nprogress插件npm i nprogress

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

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

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

请添加图片描述

注:进度条的颜色可以在nprogress.css里面进行修改。

四、Vuex模块化开发

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

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

安装vuex npm i vuex@3,Vuex知识和使用详情点击此处进行了解或复习——Vuex笔记

由于使用单一状态数时,应用的啊u哦有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。

为了解决这个问题,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的state、mutation、action、getter,甚至是嵌套子模块——从上至下进行同样方式的分割。

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中覆盖掉初始值,注意要根据接口的返回值来初始化,服务器返回对象,初始值就是对象,服务器返回数组,初始值就是数组。这里因为后台数据响应体是数组,故初始值为一个空数组

// home模块的小仓库import { reqCategoryList } from "@/api/index";const state = {//state中数据默认初始值别瞎写// 服务器返回对象,服务器返回数组。【根据接口返回值进行初识化】categoryList: [],
};
const mutations = {// 把数据接收一下传给stateCATEGORYLIST(state, categoryList) {state.categoryList = categoryList;},
};
const actions = {// 通过api里面的接口函数调用,向服务器发请求,获取服务器数据// 若成功就把数据通过commit交给mutations进行操作async categoryList({ commit }) {let result = await reqCategoryList();console.log(result);if (result.code == 200) {commit("CATEGORYLIST", result.data);}},
};
const getters = {};// 对外暴露
export default {state,mutations,actions,getters,
};

(3)TypeNav接收数据

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

这里要注意,由于仓库中数据默认值为空,一开始其实computed读到的是空,也就是在mounted中是读不到的,但是当异步请求到数据时,仓库中数据改变,也就是computed依赖的值发生了改变,那么此时根据computed的特征,get函数会重新触发,属性值改变,导致模板重新解析。所以我们才能够把异步请求到的数据传给子组件使用。(子组件先挂载,父组件再挂载)

请添加图片描述

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

请添加图片描述

然后dispatch时就要变成模块名/actions方法名,注意只要开启了命名空间,就要写home/categoryList,然后计算属性写数组或写法1的函数都行:

请添加图片描述

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

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

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

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

请添加图片描述
请添加图片描述

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

(1)采用css样式实现

直接在下面样式加上:

.item:hover {background: #e1564e
}

so easy,这对我们来说太简单了,没有挑战性,要做就做点难的,顺便练习下JS。

(2)通过JS实现

给一级分类添加鼠标经过事件和鼠标离开事件,把鼠标离开放到大div上(一级分类的div)。只要鼠标在二级和三级数据上,一级数据就会保持背景颜色。鼠标移出大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去写个背景色)

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

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

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

这个有很多种写法。

第一种写法比较简单,可以直接通过css样式display:none|block控制显示或隐藏。

第二种方法,就是用原生JS实现

请添加图片描述

第三种方法,用v-show实现

请添加图片描述

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

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

防抖与节流详细内容点击此处——防抖与节流

(1)什么是防抖

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

类似于——王者回城

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

(2)什么是节流

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

类似于——王者技能释放与CD

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

(3)三级联动节流

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

// 这种引入的方式,是把lodash全部功能函数引入,使用时_.throttle
// import _ from 'lodash';
// 最好的引入方式:按需加载
import throttle from 'lodash/throttle'
...methods:{// 鼠标进入修改响应式数据currentIndex属性//这里不能写简写形式,返回的结果就是一个函数嘛changeIndex:throttle(function(index){// index 鼠标移上某一个一级分类的元素的索引值this.currentIndex = index;},50),}

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

5、三级联动路由跳转与传参

这里要用到自定义属性,忘了或者不熟悉点击此处——js自定义属性笔记

(1)需求分析

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

路由跳转最先想到可以用<router-link></router-link>,但是这样的话<router-view>会生成好多组件,页面会卡顿。

如果只用编程式导航,要给每个a加点击事件,也不太好。这让我想到可以在编程式导航的基础上用事件委派,也就是冒泡。

事件委派忘了或者不熟悉点击此处——

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

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

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

请添加图片描述

存在一些问题:

  • 第一个问题:事件委派,是把全部的子节点【h3、dt、dl、em】的事件都委派给了父亲节点。需求是点击a标签的时候才会进行路由跳转【怎么确定点击的一定是a标签呢】

  • 第二个问题:即使确定点击的是a标签,如何区别点击的是一级、二级、三级分类的标签

解决:自定义属性

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

  • 如何获取参数【1,2,3级分类的产品的名字和ID】?
    名字好说,解构赋值都已经拿到了,主要是id怎么搞?还是自定义属性,分别给每一级别数据的a标签添加自定义属性

请添加图片描述

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

  goSearch(event) {// 最好的解决方法:编程式导航+事件委派// 存在一些问题:// 第一个问题事件委派,是把全部的子节点【h3、dt、dl、em】的事件都委派给了父亲节点。需求是点击a标签的时候才会进行路由跳转【怎么确定点击的一定是a标签呢】// 第二个问题:即使确定点击的是a标签,如何区别点击的是一级、二级、三级分类的标签// 解决:// 第一个问题:把子节点当中的a标签,加上自定义属性data-categoryName,其余的子节点是没有的// 获取当前出发这个事件的节点,需要带有data-categoryname这样的节点【一定是a标签】// 节点有一个dataset属性,可以获取节点的自定义属性与属性值let { categoryname, category1id, category2id, category3id } =event.target.dataset;// 如果标签身上拥有categoryname一定是a标签if (categoryname) {//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, //把上面定义的那玩意儿拿过来});}},

6、Search模块中三级联动的显示与隐藏

(1)实现显示与隐藏效果

需求:我们要做的是在home主页中保持显示三级联动模块,在其他组件中(如Search)默认上来隐藏,然后鼠标移入显示,鼠标离开隐藏。

  1. 我们可以在TtpeNav组件中加入一个数据show用来决定组件的显示和隐藏,默认值为true

请添加图片描述

  1. 利用v-show和数据show来判断是否显示三级导航的内容部分

请添加图片描述

  1. 当从Home进入到Search的时候,TypeNav会再重新挂载,所以当进入Search的时候,让show变成false,而且要判断只要不是往主页跳,挂载完都要隐藏(这样的话能够保证主页的三级导航一直显示,避免bug)

请添加图片描述

  1. 配置回调函数,离开时加个判断,在home中就一直显示,其他组件鼠标离开即隐藏
// 当鼠标移入时,让商品分类列表进行展示enterShow() {this.show = true;},// 当鼠标离开时,让商品分类列表进行隐藏leaveShow() {this.currentIndex = -1;if (this.$route.path != "/home") {this.show = false;}},

(2)添加过渡动画

使用transition标签包住带有v-show属性的标签,记得加个name,然后去写css样式

// 三级导航内容部分过渡动画
//过渡动画开始的状态
.sort-enter,
.sort-leave-to {height: 0px;
}//过渡动画的结束状态
.sort-enter-to,
.sort-leave {height: 461px;
}//定义动画时间,速率
.sort-enter-active,
.sort-leave-active {overflow: hidden;transition: all .1s linear;
}

7、解决三级导航ajax请求重复发送的bug

要点:所有只触发一次的行为,最好都写到app.vue中。这是因为App是唯一的根组件,它的mounted只会执行一次,且App组件早就先执行的。

之前我们是把下面这段代码写到TypeNav组件的mounted钩子中,但是这样只要home和search来回切换,就重新发起TypeNav中的数据请求,这样连续发送ajax请求不太行啊,所以我们把请求放到App.vue中,这样请求只会发送一次,想用数据直接去Vuex仓库拿就完事。

// 派发actions。通知Vuex发请求,获取商品分类三级列表的数据,存储在仓库当中this.$store.dispatch("categoryList");

8、合并params与query参数

我们往Search组件跳转有两种方式,一种是通过搜索关键字跳转,另一种是点击三级导航的链接跳转,三级导航传的是query参数,搜索关键字传的是params参数

请添加图片描述

但是这两种方式只能传一个地方的组件,如果先三级导航跳转再搜索的话,搜索传的params参数和空query参数会覆盖三级导航传的query参数和空params参数。
所以我们可以两边都通过一个判断来实现参数的合并,就是params和query参数同时到url中。

请添加图片描述

这里有个疑惑的点,当this. r o u t e . p a r a m s 或 t h i s . route.params或this. route.paramsthis.route.query为空对象时,为什么也能进if里??因为我上来直接点链接(此时明明query是空),也能跳转,好奇怪,空对象是true吗,如果是的话,那这个判断条件完全可以不写。
发现问题原因:空对象既不是true也不是false。空对象或者空数组,都是构造函数的实例化对象,ta们就算没有自定义的属性或者元素,但是其本身是有定义好的属性和方法的,所以写在if里也能够执行条件体。所以这里的if判断写了个寂寞。。。

六、开发Home首页中的ListContainer、Floor组件

由于接口返回的后端数据只有商品菜单分类数据(三级联动),对于ListContainer组件与Floor组件数据服务器没有提供,我们这里要用到mock模拟数据。mock能够模拟后台的数据,但是只是在前端自己用,前端mock数据不会和服务器进行任何通信

1、mock搭建模拟数据

mock模拟数据:如果你想mock数据,需要用到一个插件mockjs:安装npm i mockjs

1、在项目src文件夹中创建mock文件夹--------提供假数据的文件夹

2、准备JSON数据的两个文件(记得格式化一下)
(1)首页广告轮播数据: src/mock/banner.json,数据来自老师给的文件
(2)首页楼层数据: src/mock/floor.json,数据来自老师给的文件

3、把mock数据需要的图片(包括轮播图和floor)放置到public/images文件夹中【public文件夹在打包的时候,会把相应的资源原封不动打包到dist文件夹中】

4、在mock文件夹下创建mockServe.js,并利用mockjs模块模拟出来假数据,这里要注意url路径是以/mock开头的,后边配置axios时要改一下基础路径。

// 引入mockjs模块
import Mock from "mockjs";
// 把JSON数据格式引入进来
// JSON不用对外暴露也可以引入
// webpack默认对外暴露:图片、JSON数据格式
import banner from "./banner.json";
import floor from "./floor.json";// mock数据:第一个参数是请求地址,第二个参数是请求数据
Mock.mock("/mock/banner", { code: 200, data: banner }); //模拟首页大轮播图的数据
Mock.mock("/mock/floor", { code: 200, data: floor }); //模拟首页的楼层

5、在main.js里引入src/mock/mockServe.js,让配置假数据一上来就先执行一下

//引入模拟数据的js文件,让它先执行一下
import './mock/mockServe';

2、mock虚拟数据的ajax请求

之前二次封装的axios是用来给后台服务器发送ajax请求的,那虚拟数据该如何请求?很简单,只需要在api文件夹中再配置一个axios,只把其中的baseURL属性值替换成我们在src/mock/mockServe.js文件中配置的数据路径/mock

请添加图片描述

请添加图片描述

然后去统一管理API的文件(src/api/index.js)中配置轮播图部分的接口:

请添加图片描述

3、获取Banner轮播图的数据

和前边获取TypeNav三级导航数据的操作是一样的,只不过那个是真发送ajax请求从后台拿数据,这个是从我们自己模拟的假数据里拿数据

和之前获取三级联动的数据是一个套路
1、首先挂载完毕后组件派发action,调用仓库中的getBannerList函数

mounted() {// 派发actions 通知Vuex发起ajax请求,将数据存储在仓库当中this.$store.dispatch("getBannerList");},

2、去Vuex中配置getBannerList函数,通过vuex的actions发起ajax请求,将数据存储在仓库中的state。

请添加图片描述

3、组件接收数据,使用mapState语法糖

  computed: {...mapState({bannerList: (state) => state.home.bannerList,}),},或者:computed: {...mapState('home',['bannerList']),},

4、制作ListContainer轮播图

轮播图可以用这个插件:swiper的基本使用
安装:npm i swiper@5

使用swiper要分三步:
1.引入相应的包
2.页面结构必须先有(给轮播图添加静态效果)
3.有结构后再new Swiper实例(给轮播图添加动态效果)

(1)引入相应的包(js和css)

JS在对应组件内引入:

import Swiper from 'swiper';

css在main.js里引入:由于floor组件和listContainer组件都用到了轮播图,所以我们在main.js里引入swiper的样式,这样的话就都哪个组件都可以用swiper的样式了

//引入轮播图插件样式swiper
import 'swiper/css/swiper.css';

(2)搭建轮播图页面结构

carousel单词是轮播图的意思
这里做个铺垫:v-for 遍历mock返回的数据,数据返回后才会渲染遍历到页面

请添加图片描述

(3)给轮播图添加动态效果

如果把new Swiper直接放到mounted里边儿,行吗?

请添加图片描述

不行。因为dispatch去Vuex中请求数据,在actions中发送ajax请求是一个异步操作(用到了async,去看代码),这样的话,会导致new Swiper先执行,然后再去请求数据,再把数据v-for放到轮播图页面结构上。这样的话页面结构还没完整就new Swiper了,会无法正常显示(页面结构必须先生成再new Swiper)

  • 解决方法1:定时器(不推荐,因为发送ajax请求的时间不确定,所以定时器时间不好把握)
mounted() {//挂载完毕后通过Vuex发送ajax请求,将数据存储在仓库中this.$store.dispatch('home/getBannerList');setTimeout(() => {var mySwiper = new Swiper(".swiper-container", {loop: true,cssMode: true,navigation: {nextEl: ".swiper-button-next",prevEl: ".swiper-button-prev",},pagination: {el: ".swiper-pagination",clickable: true, // 点击小球的时候也切换},mousewheel: true,keyboard: true,});}, 1000);
},
  • 解决方法2:watch和$nextTick(用这个)
    watch:数据监听,监听已有数据的变化
    1、监听bannerList数据的变化,因为这条数据由空数组变为数组里面有mock数据
    2、通过watch监听bannerList属性的属性值的变化
    3、如果执行handler方法,代表组件实例身上这个属性的属性值数组已经有了mock数据
    4、但是这里 结构没有渲染完成 ,现在只能保证数据已经有了,但是没法保证v-for已经执行完成了

    $nextTick:在下次 DOM 更新,循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。当执行这个回调的时候,保证服务器的数据回来了,v-for执行完毕了【轮播图的结构已经完成了】。$nextTick可以保证页面中的结构一定是有的,经常和很多插件一起使用【都需要DOM存在】

//   文件:src/pages/Home/ListContainer
watch: {//监听bannerList数据的变化:由空数组变成mock数据bannerList: {//当bannerList从空数组变成有数据时(ajax请求成功),执行handler函数//但是,当前函数执行的时机只能保证数据有了,但是v-for是否执行结束不知道//而v-for执行完毕的时候,页面才能有结构handler(newVal, oldVal) {//nextTick能保证页面结构先渲染出来,然后再执行回调函数this.$nextTick(function () {var mySwiper = new Swiper(".swiper-container", {loop: true,cssMode: true,navigation: {nextEl: ".swiper-button-next",prevEl: ".swiper-button-prev",},pagination: {el: ".swiper-pagination",clickable: true, // 点击小球的时候也切换},mousewheel: true,keyboard: true,});})}}}

5、开发floor组件

组件首先还是拿数据,步骤和之前的一样:配置api接口 => 在actions请求数据,存储到Vuex中 => dispatch给Vuex => 拿到数据渲染到页面上

(1)从mock拿数据

1、配置api接口

//   src/api/index.js
//3.floor部分的接口
//  /mock/floor
export const reqFloorList = () => mockRequests.get('/floor');

2、数据存储到仓库

//  src/store/home/index.js
// home模块的小仓库import { reqCategoryList, reqGetBannerList, reqFloorList } from "@/api/index";const state = {//state中数据默认初始值别瞎写// 服务器返回对象,服务器返回数组。【根据接口返回值进行初识化】categoryList: [],bannerList: [],floorList: [],
};
const mutations = {CATEGORYLIST(state, categoryList) {categoryList.shift();categoryList.shift();state.categoryList = categoryList;},BANNERLIST(state, bannerList) {state.bannerList = bannerList;},FLOORLIST(state, floorList) {state.floorList = floorList;},
};
const actions = {// 通过api里面的接口函数调用,向服务器发请求,获取服务器数据async categoryList({ commit }) {let result = await reqCategoryList();// console.log("三级导航数据:"+result);if (result.code == 200) {commit("CATEGORYLIST", result.data);}},// 获取首页轮播图的数据async getBannerList({ commit }) {let result = await reqGetBannerList();// console.log("轮播图数据:" + result);if (result.code == 200) {commit("BANNERLIST", result.data);}},//获取floor数据async getFloorList({ commit }) {let result = await reqFloorList();// console.log("Floor数据:" + result);if (result.code == 200) {commit("FLOORLIST", result.data);}},
};
const getters = {};// 对外暴露
export default {state,mutations,actions,getters,
};

2、dispatch给Vuex

去哪里dispatch呢?这个要看我们的数据和home页的结构,mock数据里是数组包两个对象[{},{}],所以应该有两个Floor组件,而且每个里面的数据是不一样的,如果去floor组件里dispatch,那么没法拿里面的数据,而且两个数据怎么区分?所以要去home里dispatch

请添加图片描述

然后使用mapState拿到数据

(2)Home中的数据传给Floor

数据在home中,传给Floor——父子组件通信使用props
第一个floor用数组里的第一个对象,第二个floor用数组里的第二个对象

请添加图片描述

(3)数据渲染到Floor页面

Floor已经拿到了数据,这块儿就不难了,根据数据的结构和html结构把它们分别用v-for或插值语法渲染到页面上就行了,这里边值得注意的一个地方是这里的轮播图。

轮播图的三步使用:1.导包 2.页面结构先有 3.new Swiper实例后有

和前边不同的是,这里我们可以把new Swiper实例放在mounted里,这是因为Floor里的数据都是Home组件传过来的,而发请求是在父组件Home里面挂载完毕发的,所以传过来的数据是请求好的数据,也就是说Floor组件里面没有任何异步操作,所以挂载完毕之后页面结构就会先有,然后就直接new Swiper就行了。(之前我们是在当前组件ListContainer的内部发请求以及动态的渲染结构,必须watch+$nextTick)

<template><div class="floor"><div class="py-container"><div class="title clearfix"><h3 class="fl">{{ eachFloor.name }}</h3><div class="fr"><ul class="nav-tabs clearfix"><liclass="active"v-for="(nav, index) in eachFloor.navList":key="index"><a href="#tab1" data-toggle="tab">{{ nav.text }}</a></li></ul></div></div><div class="tab-content"><div class="tab-pane"><div class="floor-1"><div class="blockgary"><ul class="jd-list"><li v-for="(keyword, index) in eachFloor.keywords" :key="index">{{ keyword }}</li></ul><img :src="eachFloor.imgUrl" /></div><div class="floorBanner"><div class="swiper-container" ref="floor1Swiper"><div class="swiper-wrapper"><divclass="swiper-slide"v-for="carousel in eachFloor.carouselList":key="carousel.id"><img :src="carousel.imgUrl" /></div></div><!-- 如果需要分页器 --><div class="swiper-pagination"></div><!-- 如果需要导航按钮 --><div class="swiper-button-prev"></div><div class="swiper-button-next"></div></div></div><div class="split"><span class="floor-x-line"></span><div class="floor-conver-pit"><img :src="eachFloor.recommendList[0]" /></div><div class="floor-conver-pit"><img :src="eachFloor.recommendList[1]" /></div></div><div class="split center"><img :src="eachFloor.bigImg" /></div><div class="split"><span class="floor-x-line"></span><div class="floor-conver-pit"><img :src="eachFloor.recommendList[2]" /></div><div class="floor-conver-pit"><img :src="eachFloor.recommendList[3]" /></div></div></div></div></div></div></div>
</template><script>
import Swiper from "swiper";
export default {name: "",props: ["eachFloor"],mounted() {new Swiper(this.$refs.floor1Swiper, {loop: true,cssMode: true,navigation: {nextEl: ".swiper-button-next",prevEl: ".swiper-button-prev",},pagination: {el: ".swiper-pagination",clickable: true, // 点击小球的时候也切换},mousewheel: true,keyboard: true,});},
};
</script><style lang="less" scoped>
.floor {...
}
</style>

(4)把轮播图封装为全局组件

以后在开发项目的时候,如果看到某一个组件在很多地方都使用,你把它变成全局组件,注册一次,可以在任意地方使用,公用的组件 | 非路由组件放到components文件夹中。结构,样式,行为要几乎一样才能封装成全局组件,大家一起公用

我们发现ListContainer中的轮播图和Floor中的轮播图长得差不多,唯一的区别就是数据不同,还有就是ListContainer里用的watch+ n e x t T i c k (因为要异步请求数据), F l o o r 是直接写道 m o u n t e d 里,其实 F l o o r 也可以用 w a t c h + nextTick(因为要异步请求数据),Floor是直接写道mounted里,其实Floor也可以用watch+ nextTick(因为要异步请求数据),Floor是直接写道mounted里,其实Floor也可以用watch+nextTick,但是由于Floor中的数据是直接拿Home请求好的,所以要加上immediate: true(不管数据变没变先调用handeler),这样的话,轮播图组件就可以封装成以下样子:

请添加图片描述

至此Home首页就基本完结啦!!!!撒花~继续加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_169448.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无涯教程-JavaScript - COUPNCD函数

描述 COUPNCD函数返回一个数字,该数字表示结算日期之后的下一个息票日期。 语法 COUPNCD (settlement, maturity, frequency, [basis])争论 Argument描述Required/OptionalSettlement 证券的结算日期。 证券结算日期是指在发行日期之后将证券交易给买方的日期。 RequiredMa…

sqlserver2012 bat脚本实现最大使用内存设置

前言 安装完成sqlserver之后&#xff0c;在运行过程中会无限制的占用电脑的内存&#xff0c;会影响到其他软甲的使用。 bat脚本 准备好bat脚本和sql文件之后&#xff0c;配置好数据库信息 直接双击即可 ECHO OFF REM 自动判断权限问题&#xff0c;主动获取管理员权限>…

归并排序的递归和非递归实现

归并排序 平均时间复杂度O(n*logn),空间复杂度O(n) 递归实现 思路&#xff1a; 分治法 即先使每个子序列有序&#xff0c;再使子序列段间有序。若将两个有序表合并成一个有序表&#xff0c;称为二路归并。归并排序是一种稳定的排序方法 code&#xff1a; //递归版public st…

【深度学习】 Python 和 NumPy 系列教程(四):Python容器:2、元组tuple详解(初始化、索引和切片、元组特性、常用操作、拆包、遍历)

目录 一、前言 二、实验环境 三、Python容器&#xff08;Containers&#xff09; 0、容器介绍 1、列表&#xff08;List&#xff09; 2、元组&#xff08;Tuple&#xff09; 1. 初始化 a. 使用小括号() b. 省略小括号 c. tuple() 函数 2. 访问元组元素 a. 索引 b.…

XXE-Lab for PHP

环境配置 1.将靶场进行下载.... https://github.com/c0ny1/xxe-lab 2.将PHPStudy的中间件与版本信息调制为php-5.4.45Apache访问以下地址开始练习... http://127.0.0.1/xxelabs/php_xxe/ 靶场实操 1.在登录界面输入账号密码并抓取数据包.... 2.尝试读取本地文件.... <…

(其他) 剑指 Offer 67. 把字符串转换成整数 ——【Leetcode每日一题】

❓ 剑指 Offer 67. 把字符串转换成整数 难度&#xff1a;中等 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。 首先&#xff0c;该函数会根据需要丢弃无用的开头空格字符&#xff0c;直到寻找到第一个非空格的字符为…

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池

博客系统&#xff08;二&#xff09; 博客系统获取当前用户的信息对密码进行加密和解密的操作设置统一的数据返回格式设置未登录拦截设置线程池 博客系统 博客系统是干什么的&#xff1f; CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统&#xff0c;这是…

react实现一个搜索部门(input + tree)

目录 react实现一个搜索部门(input tree)searchDept.jsxtreeData.js使用组件效果 react实现一个搜索部门(input tree) searchDept.jsx import React, { useState, useEffect } from "react"; import StyleDeptId from "styled-components"; import Spl…

RabbitMQ管控台使用

安装成功RabbitMQ后&#xff0c;进入到管理控制台界面 拷贝配置文件到指定目录当中然后重启RabbitMQ。

力扣:92. 反转链表 II(Python3)

题目&#xff1a; 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#…

joplin更新后找不到文章

Joplin的数据默认是存储在C:\Users\Username.config\joplin-desktop下的。我修改为了D:\joplinnotes 这样就导致在升级覆盖安装的时候&#xff0c;笔记丢失路径。如果记不起之前笔记保存在哪里&#xff0c;也可以搜索类似文件来回忆之前自己保存笔记的位置 cache\ plugins\ re…

国内 Docker 镜像加速器和国内公共镜像仓库那些事

前言 首先我们知道&#xff0c;全球最大的公共镜像仓库是 Docker 公司自己搭建的 Docker Hub&#xff0c;也是权威性最高的&#xff0c;里面包含了各种各样的官方镜像&#xff0c;Docker Hub 为每一个注册用户提供了个人镜像仓库服务&#xff0c;该个人镜像仓库是公共的。 以上…

OpenCV实现图像的混合

原理 这其实也是加法&#xff0c;但是不同的是两幅图像的权重不同&#xff0c;这就会给人一种混合或者透明的感觉。 图像混合的计算公式如下: g(x)(1-a)f0(x) af1(x) 通过修改α的值(0→1) &#xff0c;可以实现非常炫酷的混合。 现在我们把两幅图混合在一起。 第一幅图…

基于SpringBoot+Vue前后端分离的学校心理健康测试系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 研究背景介绍&#xf…

华为云云服务器评测|详解 Nacos 安装部署

环境配置 服务器云耀云服务器L操作系统CentOS 7.9 64bit | 公共镜像JDK64 bit JDK 1.8MavenMaven 3.2.xnacos-server2.2.3 下载地址 官方githubRelease 2.2.3 (May 25th, 2023) alibaba/nacos GitHub百度网盘链接&#xff1a;https://pan.baidu.com/s/1K8UE6iJL2ZnosUY83b…

SpringBoot自动配置原理及使用流程

SpringBoot自动配置原理及使用流程 SpringBoot自动配置原理 具体流程 1、导入场景 以starter-web为例 场景启动器导入了相关场景的所有依赖&#xff0c;如&#xff1a;starter-json,starter-tomcat,spring-webmvc。 每个场景启动器都引入了一个spring-boot-starter,核心场景…

darknet识别(某验)文字点选验证码

今天介绍darknet识别文字点选验证码&#xff0c; Darknet is an open source neural network framework written in C and CUDA. darknet是基于yolo算法的神经网络框架。 废话少说先热热身 平台是Ubuntu20&#xff0c;首先要安装NVIDIA驱动 1、安装驱动 NVIDIA GeForce 驱动…

2023-09-09 LeetCode每日一题(课程表)

2023-09-09每日一题 一、题目编号 207. 课程表二、题目链接 点击跳转到题目位置 三、题目描述 你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中…

[De1CTF 2019]SSRF Me | BUUCTF

根据题目名我们知道这是一道SSRF的题目 它允许攻击者在受害服务器上发起未经授权的网络请求 分析 在buuctf上有一个提示 也就是说flag在 网站的flag.txt 访问主页 很明显是段flask代码 格式化后 from flask import Flask, request # 导入Flask和request模块 import sock…

易优cms响应式月嫂家政服务公司网站模板源码—自适应手机端设计,支持后台管理

易优cms响应式月嫂家政服务公司网站模板源码 自适应手机端 带后台 模板基于EyouCMS内核制作,模板编码为UTF8 ,适合行业:家政服务类企业。 模板信息&#xff1a; 模板分类&#xff1a;摄像、婚庆、家政、保洁 适合行业&#xff1a;家政服务类企业 模板介绍&#xff1a; 本模…