写在前面

今天是7.23,这一篇内容主要完成了Home模块和部分Search模块的开发,主要是使用了swiper轮播图插件获取vuex仓库数据展示组件以及其他信息。

1 Search模块

1.1 Search模块的全部商品分类的显示

需求分析 :在home模块中,需要显示商品分类的三级联动全局组件,而在search模块则不需要。

①在Search组件中引入typeNav全局组件,并在一级分类元素上添加v-show,在data中添加show数据

<div class="sort" v-show="show">
data() {
return {
curIndex: -1,
show: true
};
},

②在TypeNav组件的mounted函数中根据当前路由修改show的值

mounted() {
// 通知vuex向服务器发送数据,并存储于home数据仓库中
this.$store.dispatch("CategoryList");
// 当前组件不是home组件则不显示
if(this.$route.name!='home') {
this.show = false;
}
},

1.2 Search模块三级联动模块鼠标进出效果

在三级目录父元素上添加leaveShow和enterShow函数

<div @mouseleave="leaveShow()" @mouseenter="enterShow()">

并在方法中定义,其中leavaShow函数需要对当前路由进行判断,home组件的三级联动模块在鼠标移开的时候是不需要消失的

enterShow() {
this.show = true;
},
leaveShow() {
this.curIndex = -1;
if(this.$route.name != 'home') {
this.show = false;
}
},

1.3 Search模块中三级联动模块的过渡动画

transition只能和v-show或者v-if一起使用

<transition name="sort">
<div class="sort" v-show="show">
<div class="all-sort-list2"> <div class="item"
v-for="(c1, index) in CateGoryList" :key="c1.categoryId"
:class="{cur:index==curIndex}"
@click="goSearch"
> <h3 @mouseenter="changeIndex(index)">
<a :data-cateGoryName="c1.categoryName" :data-cateGory1Id="c1.categoryId">{{c1.categoryName}}</a>
</h3>
<div class="item-list clearfix" :style="{display:index==curIndex?'block':'none'}">
<div class="subitem" v-for="(c2, index) in c1.categoryChild" :key="c2.categoryId">
<dl class="fore">
<dt>
<a :data-cateGoryName="c2.categoryName" :data-cateGory2Id="c2.categoryId">{{c2.categoryName}}</a>
</dt>
<dd>
<em v-for="(c3, index) in c2.categoryChild" :key="c3.categoryId">
<a :data-cateGoryName="c3.categoryName" :data-cateGory3Id="c3.categoryId">{{c3.categoryName}}</a>
</em>
</dd>
</dl>
</div>
</div>
</div> </div>
</div>
</transition>

定义动画样式:

    // 过渡动画样式
// 过渡动画开始状态
.sort-enter{
height: 0px;
}
// 过渡动画结束状态
.sort-enter-to{
height: 461px;
}
// 定义动画的时间、速率等
.sort-enter-active{
transition: .2s linear;
// 可以解决文字的显示问题
overflow: hidden;
}

1.5 TypeNav列表优化

存在的问题:在home和search路由切换的过程里面,换出的路由会被销毁,换入的路由会重新创建,如此一来每次都需要向服务器发送请求请求列表数据,这显然是不合理的,我们需要的是每次使用只请求一次数据,然后放入输入仓库供各模块使用即可。

分析:因为要求只请求一次数据,所以可以在App根组件的mounted中向数据仓库进行派发acion的操作,TypeNav全局组件的mounted就不需要进行重复的操作了。

App.vue

<template>
<div id="app">
<Header></Header>
<router-view></router-view>
<Footer v-show="$route.meta.showFooter"></Footer>
</div>
</template> <script>
import Header from './components/Header'
import Footer from './components/Footer' export default {
name: 'App',
components: {
Header,
Footer
},
mounted() {
this.$router.push('/home');
this.$store.dispatch('CategoryList')
},
}
</script> <style>
</style>

TypeNav模块

  mounted() {
// 通知vuex向服务器发送数据,并存储于home数据仓库中
// App根组件请求一次,这里注释掉了
// this.$store.dispatch("CategoryList"); // 当前组件不是home组件则不显示
if (this.$route.name != "home") {
this.show = false;
}
},

1.6 合并参数

分析:现在Header组件TypeNav组件都可以通过goSearch方法进行路由跳转到search路由,但是Header组件会向路由通过params参数传递搜索关键字,而三级联动TypeNav组件则是通过query参数向路由传递categoryname以及三级的categoryid参数,因此需要对两种参数进行合并,如果先点击三级联动再点击搜索、或者先点击搜索再点击三级联动,出现的效果应该是两种参数的集合。

实现:在进行路由跳转之前判断一下当前路由是否含有另一个组件的params或者query参数,如果存在则添加到路由器中一起进行传递。

Header模块(使用的是params参数)

    goSearch() {
let location = {
name: "search"
}
let params = {
keyWord: this.keyWord
}
location.params = params
if(this.$route.query) {
location.query = this.$route.query
} this.$router.push(location);
}

TypeNav模块(使用的是query参数)

    goSearch(event) {
let element = event.target;
let {categoryname, category1id, category2id, category3id} =
element.dataset;
if (categoryname) {
// 整理参数
let location = {
name: "search",
};
let query = {
categoryname: categoryname,
};
if (category1id) {
query.category1id = category1id;
} else if (category2id) {
query.category2id = category2id;
} else {
query.category3id = category3id;
}
location.query = query;
// 合并参数
if (this.$route.params) {
location.params = this.$route.params
}
// 转发路由传递参数
this.$router.push(location);
}

注意!!!

想要获取到转发路由器的query参数,需要在路由配置中做如下配置:

path: '/search:keyWord'

否则将无法获取到keyWord参数

2 Home模块

2.1 ListContainer轮播图组件

2.1.1 Mock.js 生成随机书籍 拦截Ajax请求

①安装mockjs(没有点)

npm install --save mockjs

②在项目src文件目录下建立mock文件夹

③将需要模拟的数据以json的形式放在mock下

④并将其中的静态资源放到public下面,这是因为webpack打包之后所有的静态资源会被放到public下面

⑤在mock下面调用引入Mock的mock方法

mock/service.js

import Mock from 'mockjs'

import banner from './banner.json'
import floor from './floor.json' Mock.mock('/mock/banner', {code: 200, data: banner})
Mock.mock('/mock/floor', {code: 200, data: floor})floor)

webpack中json、图片是默认暴露的

⑥在main.js入口文件中引入mock

main.js

import Vue from 'vue'
import App from './App.vue'
import router from '@/router'
import TypeNav from '@/components/TypeNav'
import store from '@/store'
import '@/mock/service' Vue.config.productionTip = false;
Vue.component(TypeNav.name, TypeNav); new Vue({
render: h => h(App),
router,
store
}).$mount('#app')
2.1.2 获取Mock中Banner轮播图的数据

①在home数据仓库中添加actionsmutations以及state

store/home/index.js

import {reqCategoryList} from '@/api'
import {reqBannerList} from "@/api"; const actions = {
// 通过api中的函数调用,向服务器发送请求,获取服务器数据
async CategoryList(context) {
let result = await reqCategoryList();
if(result.code === 200) {
context.commit('CATEGORYLIST', result.data)
}
},
async BannerList(context) {
let result = await reqBannerList();
if(result.code === 200) {
context.commit('BANNERLIST',result.data)
}
}
} const mutations = {
CATEGORYLIST(state, CateGoryList) {
state.CateGoryList = CateGoryList;
},
BANNERLIST(state, BannerList) {
state.BannerList = BannerList
}
} const getters = { } const state = {
CateGoryList: [],
BannerList: []
} // 将模块仓库内容对外暴露
export default {
state,
actions,
mutations,
getters
}

②在ListContainer组件中利用mapState生成对应计算属性

  computed: {
// mapState生成vuex仓库数据的计算属性
...mapState({
BannerList: (state) => {
return state.home.BannerList
}
})
}

③在轮播图中展示数据

          <div class="swiper-wrapper">
<div class="swiper-slide" v-for="(banner, index) in BannerList" :key="banner.id">
<img :src="banner.imgUrl"/>
</div>
</div>
2.1.3 swiper 轮播图插件

①swiper插件安装

npm i --save swiper@5

更高版本的swiper需要vue3

②引入swiper样式

main.js

import 'swiper/css/swiper.css'

③创建轮播图结构

        <div class="swiper-container" id="mySwiper">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(banner, index) in BannerList" :key="banner.id">
<img :src="banner.imgUrl"/>
</div>
</div>
<!-- 如果需要分页器 -->
<div class="swiper-pagination"></div> <!-- 如果需要导航按钮 -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>

④new swiper:轮播图添加动态效果

    var mySwiper = new Swiper ('.swiper-container', {
loop: true, // 循环模式选项 // 如果需要分页器
pagination: {
el: '.swiper-pagination',
}, // 如果需要前进后退按钮
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}, // 如果需要滚动条
scrollbar: {
el: '.swiper-scrollbar',
},
})

☆在哪里创建swiper实例呢?

1.在mounted生命周期钩子中:结果轮播图无法使用,这是因为mounted是在页面渲染之后运行,但是for循环中的内容牵扯到计算属性需要动态地渲染,这就使得轮播图插件渲染的时候for循环还没有进行,也就是还没有数据,因而轮播图无法呈现。

2.在updated生命周期钩子中:轮播图正常使用,结合updated是在数据动态更新后完成,会导致同一个组件中的其他数据刷新引起轮播图的刷新

3.使用watch监视轮播图无法使用,分析其原因,在于监视属性只能保证BannerList数据发生了变化,但是不能保证for渲染完成,这就使得swiper在for循环之前进行了渲染。

  watch: {
BannerList: {
handler(newVal, oldVal) {
var mySwiper = new Swiper('.swiper-container', {
loop: true, // 循环模式选项 // 如果需要分页器
pagination: {
el: '.swiper-pagination',
}, // 如果需要前进后退按钮
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}, // 如果需要滚动条
scrollbar: {
el: '.swiper-scrollbar',
},
})
}
}
}

4.完美解决方案:watch + nextTick:nextTick包裹的函数会在下次DOM更新、循环结束之后执行回调。在修改数据之后立即使用这个方法,获取更新的DOM。

watch: {
BannerList: {
handler(newVal, oldVal) {
this.$nextTick(() => {
var mySwiper = new Swiper('.swiper-container', {
loop: true, // 循环模式选项
// 自动播放
autoplay:true,
// 如果需要分页器
pagination: {
el: '.swiper-pagination',
clickable:true,
}, // 如果需要前进后退按钮
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}, // 如果需要滚动条
scrollbar: {
el: '.swiper-scrollbar',
},
})
})
}
}
}

2.2 Floor组件

2.2.1 创建访问请求的api

/api/index.js

export const reqFloorList = () => {
return mockRequests({
url: '/floor',
method: 'get'
})
}
2.2.2 Vuex三大件

actions

    async FloorList(context) {
let result = await reqFloorList();
if (result.code === 200) {
context.commit('FLOORLIST', result.data)
}
}

mutations

    FLOORLIST(state, FloorList) {
state.FloorList = FloorList
}

state

const state = {
CateGoryList: [],
BannerList: [],
FloorList: []
}
2.2.3 在App.vue中派发floor的actions
this.$store.dispatch('FloorList')

这样做的好处是应用执行期间只需请求一次,每次路由跳转不必再发送请求,只需向vuex仓库中请求数据即可

2.2.4 在home组件中使用mapstate生成仓库数据的计算属性
    computed: {
...mapState({
FloorList: (state) => {
return state.home.FloorList
}
})
}
2.2.5 生成floor组件,并进行数据的传送
    <div>
<!-- 包含三级联动加顶部导航栏 -->
<TypeNav/>
<!-- 包含轮播图加右侧尚品汇快报 -->
<ListContainer/>
<!-- 今日推荐模块 -->
<TodayRecommend/>
<!-- 热卖排行模块 -->
<Rank/>
<!-- 猜你喜欢模块 -->
<Like/>
<!-- -->
<Floor v-for="(floor, index) in FloorList" :key="floor.id" :floor="floor"/>
</div>
2.2.6 Floor props接收数据,并进行一系列数据显示
<script>
import Swiper from "swiper";
export default {
props: ['floor'],
mounted() {
var mySwiper = new Swiper ('.swiper-container', {
loop: true, // 循环模式选项
autoplay: true,
// 如果需要分页器
pagination: {
el: '.swiper-pagination',
}, // 如果需要前进后退按钮
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}, // 如果需要滚动条
scrollbar: {
el: '.swiper-scrollbar',
},
})
}
}
</script>

注意这里的轮播图创建实例可以直接写在mounted上,这是因为数据是home组件传来的不需要动态生成,即创建实例的时候for循环不需要等待异步请求获取数据,而提前完成了渲染

展示

<template>
<!--楼层-->
<div class="floor">
<div class="py-container">
<div class="title clearfix">
<h3 class="fl">{{ floor.name }}</h3>
<div class="fr">
<ul class="nav-tabs clearfix">
<li :class="index == 0 ? 'active':'' " v-for="(nav, index) in floor.navList" :key="index">
<a :href="nav.url" 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 floor.keywords" :key="index">{{ keyword }}</li>
</ul>
<img :src="floor.bigImg"/>
</div>
<div class="floorBanner">
<div class="swiper-container" id="floor1Swiper">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(carousel, index) in floor.carouselList" :key="index">
<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="floor.recommendList[0]"/>
</div>
<div class="floor-conver-pit">
<img :src="floor.recommendList[1]"/>
</div>
</div>
<div class="split center">
<img :src="floor.bigImg"/>
</div>
<div class="split">
<span class="floor-x-line"></span>
<div class="floor-conver-pit">
<img :src="floor.recommendList[2]"/>
</div>
<div class="floor-conver-pit">
<img :src="floor.recommendList[3]"/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

2.3 共用组件提取Carsousel

可以观察到,Floor中和Home组件中都使用了轮播图,代码重复率较高,因此可以将代码拿出来成为一个公共的组件:Carsousel

components/Carsousel/index.vue

<template>
<div class="swiper-container" ref="mySwiper">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(carousel, index) in list" :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>
</template> <script>
import Swiper from "swiper"; export default {
name: 'Carouse',
props: ['list'],
watch: {
list: {
immediate: true,
handler() {
this.$nextTick(() => {
var mySwiper = new Swiper('.swiper-container', {
loop: true, // 循环模式选项
autoplay: true,
// 如果需要分页器
pagination: {
el: '.swiper-pagination',
clickable :true,
}, // 如果需要前进后退按钮
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}, // 如果需要滚动条
scrollbar: {
el: '.swiper-scrollbar',
},
})
})
}
}
}
}
</script> <style scoped> </style>

Home组件中的轮播图数据需要动态地从vuex中获取,因此采用watch+nextTick的方式。而Floor组件是从父组件中获取的数据,因此不需要采用这种方式,但是需要开启immediate模式,因为不设置的话计算属性检测不到开始的时候list的变化。综合两种写法便成了上面的代码。

【Vue项目】尚品汇(三)Home模块+Floor模块+Swiper轮播图的更多相关文章

  1. vue大型电商项目尚品汇(前台篇)day02

    现在正式回归,开始好好做项目了,正好这一个项目也开始慢慢的开始起色了,前面的准备工作都做的差不多了. 而且我现在也开始慢慢了解到了一些项目才开始需要的一些什么东西了,vuex.router这些都是必备 ...

  2. vue大型电商项目尚品汇(前台篇)day04

    这几天一直都在做项目,只是没有上传上来,即将把前台项目完结了.现在开始更新整个前台的部分 一.面包屑处理 1.分类操作 点击三级联动进入搜索产生面包屑,直接取参数中的name即可 点击x怎么干掉这个面 ...

  3. vue大型电商项目尚品汇(后台篇)day05

    今天继续是对后台管理部分的一个操作,但是快要结束了,今天结束,明天会进入一个从Vue以来,另外一个名声显著的东西了,一只耳闻从未见识,而且十分的炫酷 他就是------数据可视化Echarts,迫不及 ...

  4. vue大型电商项目尚品汇(前台篇)day05

    紧急更新第二弹,然后就剩下最后一弹,也就是整个前台的项目 一.购物车 1.加入购物车(新知识点) 加入到购物车是需要接口操作的,因为我们需要将用户的加入到购物车的保存到服务器数据库,你的账号后面才会在 ...

  5. vue大型电商项目尚品汇(前台篇)day05终结篇

    前台部分到此结束,一路走来还挺怀念,今天主要是对整个项目的完成做一个最后的收尾工作,对于功能上的需求没有什么了,主要就是项目上线的一些注意事项. 一.个人中心二级路由 当我们点击查看订单应该跳转到个人 ...

  6. vue大型电商项目尚品汇(前台篇)day01

    学完vue2还是决定先做一个比较经典,也比较大的项目来练练手好一点,vue3的知识不用那么着急,先把vue2用熟练了,vue3随时都能学. 这个项目确实很经典包含了登录注册.购物车电商网站该有的都有, ...

  7. vue大型电商项目尚品汇(后台终结篇)day06 重磅!!!

    自此整个项目前后台,全部搭建完毕. 今天是最后一天,内容很多,而且也比较常用,一个图标类数据可视化,一个后台的权限管理,都是很经典的类型. 一.数据可视化 1.简介 专门的一门学科,有专门研究这个的岗 ...

  8. vue大型电商项目尚品汇(后台篇)day01

    开始我们后台篇的内容,前面处理了一些事情,去学校完成授位仪式,由校长授位合影,青春不留遗憾,然后还换了一个电脑,征战了四年的神船终于退役了,各种各样的小毛病是真的烦人. 现在正式开始后台篇的内容,做了 ...

  9. vue大型电商项目尚品汇(后台篇)day03

    今天把平台属性的管理基本完成了,后台管理做到现在基本也开始熟悉,确实就是对ElementUI的一个熟练程度. 一.平台属性管理 1.动态展示数据 先把接口弄好,应该在第三级标题选择后进行发请求 静态页 ...

  10. vue大型电商项目尚品汇(后台篇)day04

    昨天太晚就没来得及更新,今天是spu管理界面,这个界面一共有三个界面需要切换,完成了两个界面,而且今天的难度在于最后两个章节,富有一定的逻辑性,当然中间也有很多需要注意的,比如ElementUI的照片 ...

随机推荐

  1. C语言初级阶段7——指针2——特殊指针

    C语言初级阶段7--指针2--特殊指针 指针函数:是一个函数,返回值类型是一个指针. #include<stdio.h> int* fun() { //a是一个局部变量 int a = 1 ...

  2. CentOS7安装 Redis5 单实例

    1.下载redis下载地址在:redis.io比如把Redis安装到/usr/local/soft/ cd /usr/local/soft/ wget http://download.redis.io ...

  3. heimaJava17

    java IO流 缓冲流 概念 缓存流也称为高效流.或者高级流.之前学习的字节流也可以称为原始流 作用:缓冲流自带缓冲区.可以提高原始字节流.字符流读写数据的性能 分类 字节缓冲流 字节缓冲输入流:B ...

  4. OO_Lab0总结博客

    OO_Lab0 问题描述 对表达式结构进行建模,将表达式中非必要的括号进行展开并化简. 设定的形式化表述(仅写出部分): 表达式 \(\rightarrow\) 空白项 [加减 空白项] 项 空白项 ...

  5. ASP.NET WEBAPI 获取微信ticket

    public static string GetTicket(string AccessToken) { //类型 string Type = "jsapi"; string st ...

  6. 三、Applied visual design(应用视觉设计)

    一.文本属性整理 <style> h2 { /* 文字对齐属性 text-align */ /* center:居中,left,right:居左居右,justify:文字拉伸铺满一行 */ ...

  7. hbase 集群写入能力优化-预分区、TTL的应用

    一.概述 hbase 写入优化除了参数配置之外,很大的一块要考虑避免region的热点问题,避免region 热点问题,主要的目的是提高hbase 数据表rowkey的分散.结合实际情况主要有以下几个 ...

  8. 007使用IDEA开发

    007使用IDEA开发 1.什么叫IDE? 集成开发环境(IDE,Integrated Development Environment)是用于提供程序开发环境的应用程序,一般包括代码编辑器.编译器.调 ...

  9. python求列表中某个值第一次出现的位置

    x=[2,1,1] print(x.index(1)) 结果为1

  10. day2Java程序基础

    Java程序基础 Java程序基本结构 一个程序的基本单位是class,class是关键字 类名要求: 类名必须以英文字母开头,后接字母,数字和下划线的组合 习惯以大写字母开头 public除了修饰类 ...