毕设home系列【1】

本文介绍了如何将Home模块的静态页面拆分为独立组件,使用axios进行基础和响应拦截,实现接口统一管理和跨域处理。还涉及了Vue组件的生命周期、nprogress进度条、vuex状态管理,以及三级联动组件的动态样式控制、路由跳转参数处理和合并params/query。
摘要由CSDN通过智能技术生成

1.Home模块组件拆分

  1. 先把静态页面完成
  2. 拆分出静态组件
  3. 获取服务器的数据进行展示
  4. 动态业务

在这里插入图片描述
在这里插入图片描述

导航栏这儿是个二级联动,拆分为全局组件,可以在项目的任意地方使用

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

2.axios二次封装

XMLHttpRequest、Fetch、JQ、axios

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

cnpm install --save axios

api文件夹放axios请求

// 对于axios进行二次封装
import axios from 'axios';
// 请求和响应拦截器
// 1:利用axios对象的方法create,去创建一个axios实例
// 2:request就是axios,只不过我们可以自己配置一些属性
const requests = axios.create({
    // 创建配置对象
    // baseURL:基础路径,发请求的时候都带上/api,就不用自己手动写了
    baseURL: "/api",
    // timeOut:代表请求超时的时间5S
    timeout: 5000,
})
// 拦截器(interceptors)
// 请求拦截器:在发请求之前可以监测到,可以做一些事情
requests.interceptors.request.use((config) => {
    // config:配置对象,对象里面有一个属性很重要,是headers请求头
    return config;
});
// 响应拦截器:成功的回调,会返回服务器带来的数据;失败的回调,终止promise链
requests.interceptors.response.use((res) => {
    return res.data;
}, (error) => {
    return Promise.reject(new Error('fail'));
});

// 对外暴露
export default requests;

3.接口统一管理

  1. 项目很小:完全可以组件的生命周期函数中发请求,在mounted或者created中发请求,获取到服务器的数据,存储到data中。

3.1跨域问题

跨域:协议、域名、端口号不同请求,称之为跨域

办法:JSONP、CROS、代理

4.nprogress进度条插件的使用

cnpm i --save nprogress

5.vuex状态管理库

state
mutations
actions
getters
modules

import Vue from 'vue';
import Vuex from 'vuex';
// 需要使用插件一次
Vue.use(Vuex);
// state:仓库存储数据的地方
const state = {};
// mutations:修改state的唯一手段
const mutations = {};
// actions:处理actions,可以书写自己的业务逻辑,处理异步任务
const actions = {};
// getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {};

// 对外暴露store类的一个实例
export default new Vuex.Store({
    // Vuex的配置对象,key值不能瞎写
    state,
    mutations,
    actions,
    getters
});

注意vuex是3版本

5.1vuex实现模块式开发

如果项目过大,组件过多,接口也很多,数据也很多,如果有100个模块,state数据太多
模拟state数据

{
	count:1,
	search:{a:1},
	detail:{xxx},
	pay:{xxx}}

大仓库拆分出许多小仓库

返回的数据是数组形式

// 引入请求
import { reqNavList } from '@/api'
// home模块的小仓库
// state:仓库存储数据的地方
const state = {
    // state的初始值:根据接口的返回值写,是数组,还是对象
    navList: [],
};
// mutations:修改state的唯一手段
const mutations = {
    NAVLIST(state, navList) {
        // 修改state中navList的数据
        state.navList = navList;
    }
};
// actions:处理actions,可以书写自己的业务逻辑,处理异步任务
const actions = {
    // 通过API里面的接口函数,向服务器发请求,获取服务器的数据
    // 解构commit,提交mutation
    async navList({
        commit
    }) {
        // 调用reqNavList函数
        let result = await reqNavList();
        if (result.code == 200) {
            // 提交的数据是result.data
            commit("NAVLIST", result.data);
        }
    }
};
// getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {};
export default {
    // Vuex的配置对象,key值不能瞎写
    state,
    mutations,
    actions,
    getters
}

在这里插入图片描述
三级分类

      <div class="sort">
        <div class="all-sort-list2">
          <!-- 一级分类【替换】 -->
          <!-- c1是一级分类的对象,index是索引值,navList是计算属性的属性,key值是找id-->
          <div class="item" v-for="(c1,index) in navList" :key="index">
            <h3>
              <a href="">{{ c1.categoryName }}</a>
            </h3>
            <div class="item-list clearfix">
              <!-- 二级分类 -->
              <div class="subitem" v-for="(c2,index) in c1.categoryChild" :key="index">
                <dl class="fore">
                  <dt>
                    <a href="">{{c2.categoryName}}</a>
                  </dt>
                  <dd >
                    <em v-for="(c3,index) in c2.categoryChild" :key="index">
                      <a href="">{{c3.categoryName}}</a>
                    </em>
                  </dd>
                </dl>
              </div>
            </div>
          </div>
        </div>
      </div>

6.完成一级分类动态添加背景颜色

给父盒子添加离开函数,事件委派
事件委派:指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件

<template>
  <!-- 商品分类导航 -->
  <div class="type-nav">
    <div class="container">
      <div @mouseleave="leaveIndex">
        <h2 class="all">全部信息分类</h2>
        <div class="sort">
          <div class="all-sort-list2">
            <!-- 一级分类【替换】 -->
            <!-- c1是一级分类的对象,index是索引值,navList是计算属性的属性,key值是找id-->
            <div
              class="item"
              v-for="(c1, index) in navList"
              :key="index"
              :class="{ cur: currentIndex == index }"
            >
              <h3 @mouseenter="changeIndex(index)">
                <a href="">{{ c1.categoryName }}</a>
              </h3>
              <div class="item-list">
                <!-- 二级分类 -->
                <div
                  class="subitem"
                  v-for="(c2, index) in c1.categoryChild"
                  :key="index"
                >
                  <dl class="fore">
                    <dt>
                      <a href="">{{ c2.categoryName }}</a>
                    </dt>
                    <!-- 三级分类 -->
                    <dd>
                      <em v-for="(c3, index) in c2.categoryChild" :key="index">
                        <a href="">{{ c3.categoryName }}</a>
                      </em>
                    </dd>
                  </dl>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <!-- 导航栏 -->
      <nav class="nav">
        <a href="###">紧急寻亲</a>
        <a href="###">寻亲登记</a>
        <a href="###">寻亲专区</a>
        <a href="###">公益捐助</a>
        <a href="###">互助社区</a>
        <a href="###">焦点摄影</a>
        <a href="###">援助驿站</a>
        <!-- <a href="###">我们的行动</a> -->
      </nav>
    </div>
  </div>
</template>

<script>
// 开始从仓库中捞数据
// mapState辅助函数
import { mapState } from "vuex";
export default {
  name: "TypeNav",

  data() {
    return {
      currentIndex: -1,
    };
  },

  mounted() {
    // 通知Vuex发请求,获取数据,存储于仓库当中
    // 派发action
    this.$store.dispatch("navList");
  },
  // 映射为组件身上的一个实例对象,计算属性
  computed: {
    ...mapState({
      // 属性名:属性值(是一个函数)
      // 右侧为啥是一个函数呢?当使用这个计算属性的时候,右侧的函数会立即执行一次,会注入一个参数state,state即为大仓库中的数据
      // 箭头函数的简写形式,去掉return,去掉花括号
      navList: (state) => state.home.navList,
    }),
  },

  methods: {
    // 鼠标进入修改响应式数据currentIndex
    changeIndex(index) {
      // index:鼠标移上某一级分类的元素的索引值
      this.currentIndex = index;
    },
    leaveIndex() {
      // index:鼠标移出的时候currentIndex,变为-1
      this.currentIndex = -1;
    },
  },
};
</script>

7.通过js控制二三级商品分类的显示与隐藏

v-show=“currentIndex == index”
去掉css的display:none

8.完成三级联动节流的操作

依赖lodash插件

// 默认暴露的,不用加小括号{throttle}
import throttle from “lodash/throttle”;
changeIndex: throttle(function (index) {
// index:鼠标移上某一级分类的元素的索引值
this.currentIndex = index;
}, 50),

<script>
// 开始从仓库中捞数据
// mapState辅助函数
import { mapState } from "vuex";
// 引入lodash:是把lodash全部功能函数引入
// 最好的引入方式:按需加载
// 默认暴露的,不用加小括号{throttle}
import throttle from "lodash/throttle";
export default {
  name: "TypeNav",

  data() {
    return {
      currentIndex: -1,
    };
  },

  mounted() {
    // 通知Vuex发请求,获取数据,存储于仓库当中
    // 派发action
    this.$store.dispatch("navList");
  },
  // 映射为组件身上的一个实例对象,计算属性
  computed: {
    ...mapState({
      // 属性名:属性值(是一个函数)
      // 右侧为啥是一个函数呢?当使用这个计算属性的时候,右侧的函数会立即执行一次,会注入一个参数state,state即为大仓库中的数据
      // 箭头函数的简写形式,去掉return,去掉花括号
      navList: (state) => state.home.navList,
    }),
  },

  methods: {
    // es5的写法,kv形式
    changeIndex: throttle(function (index) {
      // index:鼠标移上某一级分类的元素的索引值
      this.currentIndex = index;
    }, 50),

    leaveIndex() {
      // index:鼠标移出的时候currentIndex,变为-1
      this.currentIndex = -1;
    },
  },
};
</script>

9.三级联动组件的路由跳转与传递参数

Home模块跳转到seekfamily模块:

  1. 一级会把用户选择的名字在路由跳转的时候进行传递
  2. path: “/SeekFamily/:keyword?“加问号,三级联动就可以直接跳转
    < router-link to=”/SeekFamily”>{{ c1.categoryName }}< /router-link >

  3. 但是容易出现卡顿的现象

利用事件委派存在一些问题:
4. 怎么确定点击一定是a标签
5. 路由跳转需要参数,如何获取

事件委派+编程式导航
利用自定义属性
如果a标签有data-categoryName一定就是a标签,其余子节点是没有的
HTML允许自定义属性以data-开头即为自定义属性

          <div class="all-sort-list2" @click="goSeek">
            <!-- 一级分类【替换】 -->
            <!-- c1是一级分类的对象,index是索引值,navList是计算属性的属性,key值是找id-->
            <div
              class="item"
              v-for="(c1, index) in navList"
              :key="index"
              :class="{ cur: currentIndex == index }"
            >
              <h3 @mouseenter="changeIndex(index)">
                <a
                  :data-categoryName="c1.categoryName"
                  :data-category1Id="c1.categoryId"
                  >{{ c1.categoryName }}</a
                >
              </h3>
              <!-- 二、三级分类 -->
              <div class="item-list" v-show="currentIndex == index">
                <!-- 二级分类 -->
                <div
                  class="subitem"
                  v-for="(c2, index) in c1.categoryChild"
                  :key="index"
                >
                  <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="index">
                        <a
                          :data-categoryName="c3.categoryName"
                          :data-category3Id="c3.categoryId"
                          >{{ c3.categoryName }}</a
                        >
                      </em>
                    </dd>
                  </dl>
                </div>
              </div>
            </div>
          </div>

  
   goSeek(event) {
      // 最优解:编程式导航+事件委派
      let element = event.target;
      // 节点有一个属性dataset,可以获取节点的自定义属性和属性值
      // 浏览器自动识别data-xxx,注意获取到的xxx都是小写
      let { categoryname, category1id, category2id, category3id } =
        element.dataset;
      if (categoryname) {
        // 一级分类、二级分类、三级分类的判断
        // 整理路由跳转的参数
        let location = { name: "SeekFamily" };
        // query参数需要动态添加,没办法区分一级、二级、三级
        let query = { categoryName: categoryname };
        if (category1id) {
          query.category1Id = category1id;
        } else if (category2id) {
          query.category2Id = category2id;
        } else {
          query.category3Id = category3id;
        }
        console.log(location,query);
        // 整理完参数
        location.query = query;
        // 路由跳转
        this.$router.push(location);
      }
    },

10.合并params和query参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值