当前位置:   article > 正文

vue2项目(三)----- Home_home.vue代码

home.vue代码

 Home页面有7个子组件。

1. TypeNav三级联动组件,在home,search,detail组件都在使用,所以可以注册为全局组件,这样只需要注册一次,就可以在项目的任意地方使用。

步骤:

1)创建组件(命名为TypeNav,全局组件一般放在components文件夹中)

 2)全局注册组件(在main.js文件中)

  1. // 三级联动组件(全局组件)
  2. import TypeNav from './components/TypeNav'
  3. // 全局组件:第一个参数是全局组件的名字,第二个参数是哪个组件
  4. Vue.component(TypeNav.name,TypeNav)

3)使用组件(在home组件中使用TypeNav)

  2. 完成其余的组件

步骤一样,先创建组件,再在Home组件中引入和注册并使用

 说明:

1)本项目是一个前后台分离的项目: 前台应用与后台应用

2)后台应用负责处理前台应用提交的请求, 并给前台应用返回json数据

3)前台应用负责展现数据, 与用户交互, 与后台应用交互

 3. 前后端交互AJAX

1)先安装axios

npm install -S axios nprogress

2)axios一般存放在api文件夹(自己创建)里面

index.js---对api进行统一管理

ajax.js---二次封装axios

二次封装的原因:在本项目中需要使用到请求拦截器和响应拦截器

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

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

  1. 在/api/ajax.js
  2. // 二次封装axios
  3. import axios from 'axios'
  4. const service = axios.create({
  5. baseURL: '/api',//基础路径
  6. timeout: 15000//连接请求超时时间
  7. })
  8. // 请求拦截器
  9. service.interceptors.request.use((config) => {
  10. // 必须返回配置对象
  11. return config;
  12. })
  13. // 响应拦截器
  14. service.interceptors.response.use(
  15. (response) => {
  16. // 返回响应体数据
  17. return response.data
  18. }, (error) => {
  19. // 统一处理一下错误
  20. alert(`请求出错: ${error.message || '未知错误'}`)
  21. // 后面可以选择不处理或处理
  22. return Promise.reject(error)
  23. })
  24. export default service

3)api接口的统一管理

项目很小:可以在组件的生命周期函数里发请求

项目大:使用axios.get('xxx')

  1. // 对接口的统一管理
  2. import ajax from './ajax.js'
  3. // 获取商品的三级分类列表
  4. // /api/product/getBaseCategoryList get 无参数
  5. export const reqBaseCategoryList=()=>{
  6. return ajax({url:'api/product/getBaseCategoryList',method:'get'})
  7. }
  8. // export const reqBaseCategoryList=()=>ajax.get(`api/product/getBaseCategoryList`)

4)引入进度条

先安装cnpm install --save nprogress

4.vuex模块化开发

注意:

1)vue2使用vuex3 , vue3使用vuex4

2)项目小的,可以不用vuex;项目大的,组件多的,需要使用vuex

操作流程:给每一个模块创建小仓库,再把小仓库引入到大仓库中

步骤:

1)先创建大仓库(store/index.js),再创建小仓库(store/home.js)

  1. //在store/home.js中
  2. import { reqBaseCategoryList } from '@/api'
  3. const home={
  4. state:{
  5. baseCateGoryList:[]
  6. },
  7. mutations:{
  8. RECEIVE_BASE_CATEGORY_LIST(state,list){
  9. list.shift()//去除数组的第一个元素
  10. state.baseCateGoryList=list
  11. },
  12. },
  13. actions:{
  14. async getBaseCateGoryList({commit}){
  15. const result=await reqBaseCategoryList()
  16. if(result.code==200){
  17. commit('RECEIVE_BASE_CATEGORY_LIST', result.data)
  18. }
  19. }
  20. },
  21. getters:{},
  22. namespaced:true
  23. }
  24. export default home

2)在大仓库里引入小仓库home 

  1. 在store/index.js
  2. // 大仓库
  3. import Vue from 'vue'
  4. import Vuex from 'vuex'
  5. // 需要使用插件一次
  6. Vue.use(Vuex)
  7. import home from './home'
  8. // 对外暴露store类的一个实例
  9. export default new Vuex.Store({
  10. // 实现Vuex仓库模块化开发存储数据
  11. modules:{
  12. home,
  13. }
  14. })

3)在main.js中,引入store

  1. // 引入仓库
  2. import store from './store'
  3. new Vue({
  4. render: h => h(App),
  5. // 注册路由
  6. router:router,
  7. // 注册仓库:
  8. store
  9. }).$mount('#app')

 5. 实现TypeNav三级动态联动(向服务器发送请求,获取数据,进行展示)

1)当组件挂载完毕后,可以向服务器发送请求

  1. //在TypeNav/index.vue中
  2. mounted(){
  3. this.$store.dispatch('home/getBaseCateGoryList')
  4. },

2)去home仓库请求数据

actions在执行时,会调用api里面的接口函数,向服务器发请求,调用api里的reqBaseCategoryLis函数发送。

请求成功后,把数据给mutations处理。

再把数据给state。

3)TypeNav接收数据

4)渲染数据

注意
1. home仓库使用了namespaced,开启了命名空间,在使用仓库时,记得添加/home
2. 在使用vuex模块化时,需要向外暴露一个对象,不需要用到createStore。所以给home里面命名一下,并向外暴露。
3.注意vuex3和vuex4的区别 。

6. 给三级联动的一级分类添加背景颜色,二三级进行显示与隐藏

步骤:

1)首先设置一个动态属性 currentindex=-1 ,表示鼠标都没有移上去。

  1. //在TypeNav/index.vue中
  2. data() {
  3. return {
  4. // 响应式属性,存储用户鼠标移上哪一个一级分类
  5. currentIndex: -1, // 代表鼠标谁都没有移上去
  6. };
  7. },

2) 添加一个less属性,设置背景颜色

3)给一级分类添加鼠标进入和离开事件。进入时,需要携带参数索引号,表示是哪一个一级分类。

:class="{cur: currentIndex === index} 为真时,就给当前的一级分类添加背景颜色。

  1. //在TypeNav/index.vue中
  2. <div class="item" v-for="(c1, index) in baseCateGoryList" :key="c1.categoryId"
  3. @mouseleave="leaveIndex">
  4. <h3 @mouseenter="changeIndex(index)" :class="{ cur: currentIndex === index }" >
  5. <a>{{ c1.categoryName }}</a>
  6. </h3>
  7. </div>
  8. methods: {
  9. // 鼠标进入修改响应式数据currentIndex属性
  10. changeIndex(index) {
  11. // index 鼠标移上某一个一级分类的元素的索引值
  12. this.currentIndex = index;
  13. },
  14. // 一级分类鼠标移出的事件回调
  15. leaveIndex(){
  16. // 鼠标移出currentIndex=-1
  17. this.currentIndex =-1;
  18. }
  19. },

4)使用原生JS实现二三级分类的显示与隐藏(利用三元表达式实现)

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

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

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

本项目中,鼠标不停的在三级联动上来回切换,进行节流操作,把频繁触发变为少量触发。

这里需要使用 lodash,一般都下载好了的。并且进行按需加载。

  1. //在TypeNav/index.vue中
  2. //按需引入节流
  3. import throttle from "lodash/throttle";
  4. methods: {
  5. // 鼠标进入修改响应式数据currentIndex属性
  6. // throttle回调函数不要用箭头函数,防止出现上下文this问题
  7. changeIndex: throttle(function (index) {
  8. // index:鼠标移上某一个一级分类的元素的索引值
  9. this.currentIndex = index;
  10. }, 50),
  11. },

 8.三级联动的路由跳转(从home跳转到search)

需求:当点击某个分类时,进行路由跳转,并把分类的名字和id传给search,然后search拿到参数向服务器发请求,显示相应的数据。

路由跳转的两种方式:声明式导航和编程式导航。

如果使用声明式导航,需要使用<router-link></router-link>,并且<router-view>会生成好多组件,会出现页面的卡顿。

如果使用编程式导航,需要给每一个a添加点击事件。

这里使用编程式导航+事件委派。

事件委派:在父节点上添加事件监听器,利用事件冒泡影响每一个子节点。

注意两个问题:

1)事件委派,是把全部的子节点的事件委派给父亲节点,如何确定我们点击的一定是a标签

利用自定义属性,给子节点中的a标签添加自定义属性data-categoryName,其余子节点没有。

2)确定了点击的是a标签,如何区分是一级,二级,三级分类的标签

同样也是利用自定义属性,给子节点中的a标签添加自定义属性data-category1Id、data-category2Id、data-category3Id。

步骤:先判断是不是a标签,是则进一步判断是哪一个分类。

1)先给一级分类的父标签添加点击事件,进行路由跳转。

2)给每一分类级的a标签添加自定义属性。

 3)编写跳转函数

  1. //进行路由跳转
  2. // 从home跳转到search
  3. goSearch(event){
  4. //获取当前事件的触发对象
  5. let element=event.target;
  6. //利用节点的dataset属性,获取节点的自定义属性(要小写)
  7. let { categoryname, category1id, category2id, category3id }=element.dataset;
  8. //判断,如果categoryname为真,则表示当前点击的是a标签
  9. if(categoryname){
  10. //整理路由跳转的参数
  11. let location={name:'Search'};//记得在router/index.js中给search命名
  12. // 小写的是自定义属性值,大写的是新添加的属性值
  13. // 需要获取小写的自定义属性值给大写的新添加的属性值
  14. let query={categoryName:categoryname};
  15. // 判断是一级,二级,三级哪一个分类
  16. if(category1id){
  17. query.category1Id=category1id;
  18. }else if(category2id){
  19. query.category2Id=category2id
  20. }else {
  21. query.category3Id=category3id
  22. }
  23. //此时query里面就有了name和id
  24. //再把query给到location
  25. location.query=query;
  26. //现在进行传参
  27. this.$router.push(location)
  28. }
  29. }

9.Search模块中三级联动的显示与隐藏和添加过渡动画效果

步骤:

1)先给TypeNav组件添加一个属性show,表示显示与隐藏三级联动。

2)给三级联动使用v-show,进行显示与隐藏。

3)在搜索页面,最开始三级联动是隐藏的,只有当鼠标移上去,才显示出来。

所以,当组件挂载完毕后,如果不是home组件,就隐藏三级联动

4) 鼠标在全部商品分类上移入移出,进行三级联动的显示与隐藏。

这里可以调用事件委派,给透明封装一个大盒子,在大盒子上进行鼠标移入移出事件。

 5)添加过渡动画

注意:

1)组件或者元素务必要有v-if或者v-show指令

2)记得加一个name,使用transition标签包住

  1. // 过渡动画的样式
  2. // 过渡动画开始的状态(进入)
  3. .sort-enter {
  4. height: 0px;
  5. }
  6. // 过渡动画结束状态(进入)
  7. .sort-enter-to {
  8. height: 461px;
  9. }
  10. // 定义动画时间、速率
  11. .sort-enter-active {
  12. transition: all 0.5s linear;
  13. }

10.TypeNav组件在进行路由跳转时,会传递参数,就需要发送ajax请求,每一次跳转都会发一次请求,很耗性能,需要进行优化!

操作:最开始的时候,发送请求是在TypeNav组件中的mounted钩子函数中,现在把请求放入到App.vue文件中。因为最先执行的就是App.vue,这样请求就只会发送一次!!!

11.合并参数,实现跳转时的params参数和query参数都可以传递

从首页向Search组件跳转有两种方式:

1.通过搜索关键字跳转(传的是params参数)

2.点击三级导航的链接跳转(传的是query参数)

如果既点击了搜索按钮,又点击了三级导航的链接,那么点击的后者的参数会覆盖前者的参数,所以需要进行参数的合并,这样两个参数都可以传递!!!

  1. //在Header.vue中
  2. methods:{
  3. //在搜索框输入params参数后,点击搜索按钮进行跳转
  4. search(){
  5. // this.$router.push(`/search/${this.keyword}`)
  6. //这里进行参数合并,query和params
  7. let location={name:'Search',params:{keyword:this.keyword||undefined}}
  8. location.query=this.$route.query;
  9. this.$router.push(location)
  10. }
  11. }

在TypeNav/index.js中 

12.开发首页的ListContainer(轮播图)、Floor(底部)组件 


 首先使用mock搭建模拟数据

步骤:

1)先安装:npm install mockjs

2)在src文件夹中创建mock文件夹,用来存放json假数据

3)在mock文件夹中准备假数据,引入ListContainer、Floor的数据

4)在public下创建一个images文件夹,把mock数据需要的图片存放进去

5)在mock文件夹下创建mockServe.js,通过Mock.mock方法进行模拟数据

6)在main.js里引入src/mock/mockServe.js,让配置假数据执行一次

7)在api文件夹中创建mockAjax.js文件,模拟发送请求。

里面的内容与原先二次封装的request.js文件中内容一样,但是要注意,记得把基础路径改为'/mock',因为我们是模拟发送请求

8)在src/api/index.js文件中,进行api的统一管理,模拟轮播图的接口


其次,获取轮播图数据

1)在组件挂载完毕后,向服务器发送请求

 2)使用vuex三连环

3)接收数据

 

然后,绘制轮播图 

这里需要使用swiper插件

安装swiper插件:npm i swiper --save

使用swiper的三步骤:

1.引入相应的包

2.页面结构必须先有(给轮播图添加静态效果)

3.有结构后再new Swiper实例(给轮播图添加动态效果)

步骤:

1.引包

1)在main.js中引入css(这样组件都可以使用)

  1. // 引入swiper样式
  2. import 'swiper/css/swiper.css'

2)在listContainer组件中引入swiper

  1. // 引包
  2. import Swiper from 'swiper'

2.搭建轮播图页面的结构

3.添加动态效果(重点)

    这里要注意,不能直接在mounted里面写,一般情况下在里面写是正确的。但这里不行,这里有dispatch,涉及到异步语句,需要发请求,拿数据,导致v-for遍历的时候,结构还没有完全,所以还不能实例化swiper。

    如果直接在里面写,会先实例化swiper,再搭建结构,这样是不符合swiper操作步骤的。

    页面结构必须先生成,再new Swiper!!!

解决方法:

1)使用定时器包裹swiper,但是有问题,因为发送ajax请求的时间不确定,所以定时器时间不好把握。

2)使用watch监听,但是只使用watch,只能监听到数据的变化,不能判断v-for已经执行完毕了,所以也不行。

3)使用watch+$nextTick,在监听到数据回来后,结构完成后,使用$nextTick来实例化swiper,就可以完成动态效果渲染。

所以使用方法三。

  1. //在Home/ListContainer.vue
  2. watch:{
  3. // 监听banners数据的变化,有空数组变为数组里有4个元素
  4. banners:{
  5. immediate:true,
  6. handler(newValue,oldValue){
  7. // 通过监听banners属性值的变化,如果执行了Hanler,则表示数据有了,
  8. //但是只能保证有数据了,不能保证v-for已经执行完毕
  9. //只有v-for执行完后,才有结构,才能实例化swiper
  10. //所以这里需要添加$nextTick
  11. // nextTick:在下次DOM更新, 循环结束之后,执行延迟回调。在 修改数据之后 立即使用这个方法,获取更新后的DOM。
  12. this.$nextTick(()=>{
  13. // 下面的是直接复制的swiper里面的代码
  14. var mySwiper = new Swiper ('.swiper', {
  15. loop: true, // 循环模式选项
  16. autoplay:true,//自动切换
  17. // 如果需要分页器
  18. pagination: {
  19. el: '.swiper-pagination',
  20. clickable:true,
  21. },
  22. // 如果需要前进后退按钮
  23. navigation: {
  24. nextEl: '.swiper-button-next',
  25. prevEl: '.swiper-button-prev',
  26. },
  27. })
  28. })
  29. }
  30. }
  31. }

开发floor组件

和前面一样,先写静态,之后发请求(写api),写完api之后就写仓库三连环,仓库存储数据后,组件捞数据,捞完之后展示。

1)配置api接口

2)仓库三连环存储数据

在store/home.js中写vuex三连环

3)派发action

注意,这里不能在floor组件里面派发,因为这里有两个floor组件,需要使用v-for遍历,所以在他的父组件home组件去派发。

4)收取数据

因为现在这个数据在父组件home里,子组件floor想要得到数据,就得使用组件间的通信,这里使用父向子传。

使用props传递。

5)渲染数据到页面

6)floor轮播图制作

注意在这里就可以直接在mounted里面实例化swiper。

因为这里请求是父组件发的,父组件通过props传递过来,并且结构已经有了,才执行的mounted


封装Carsouel全局组件

因为在ListContainer和Floor中都用到了carsouel轮播图,我们可以封装成一个全局组件,这样方便使用。

封装成为全局组件,注意里面的内容都是一样的,所以需要修改一下原先的内容。

由于floor组件的是父亲传过来的值,所以里面数据已经有了,所以数据没有变化,无法通过watch监听到,所以要使用immediate,立即监听。

由于ListContainer组件的v-for结构还不能确定已经完成了,所以要使用nextTick

然后两者一结合,写在components文件夹里面创建的一个Carousel文件夹中。

这样当需要使用轮播图的时候,直接引入这个文件就可以了。

注意:全局组件记得在main.js中引入并注册!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/69829
推荐阅读
相关标签
  

闽ICP备14008679号