Vue2项目实战--b站尚硅谷--尚品汇项目--详细笔记--day02

1 编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误

路由跳转由两种形式:编程式导航(push|replace)、声明式导航router-link

编程式导航才会有这种情况的异常,声明式导航是没有这种问题,因为声明式导航内部已经解决这种问题

这种异常,对于程序没有任何影响的

1.1 编程式导航为什么会出现这种现象

由于vue-router最新版本3.5.2,引入了promise,当传递参数多次且重复,会抛出异常,因此出现上面现象

我们可以把push看作一个函数,返回的是一个Promise函数,需要给函数传入成功或者失败的回调,没传 就会警告
function push(){
	return new Promise( resolve, reject ) => {
    }
}

第一种解决方案:是给push函数,传入相应的成功的回调与失败的回调(空的箭头函数就可以),还可以捕获当前的错误

      this.$router.push(
        {
          name: "search",
          params: { keyword: this.keyword },
          query: { k: this.keyword.toUpperCase() },
        },
        //解决编程式导航多次点击报错的问题 这个方案不能根治,以后再用`push|replace`还是会出现类似现象
        () => {},
        () => {}
      );

1.2 研究push

this:当前组件实例(search

this.$router属性:是VueRouter类的一个实例,当在入口文件注册路由时,给组件实例添加$router|$route属性

pushVueRouter实例身上没有push,是在VueRouter实例原型对象身上的一个方法

简单来说就是 $routerVueRouter类的一个实例,pushVueRouter原型身上的方法

所以对原型方法push进行修改,修改结果就会作用于组件实例的$router(重写push方法)

//说明实例 和 原型对象上的方法
function VueRouter(){}
//原型对象身上的方法
VueRouter.prototype.push = function(){
    //函数上下文为VueRouter类的一个实例
}
//相当于
let $router = new VueRouter();
//就可以使用原型对象身上的方法
$router.push()
console.log(VueRouter)----->是一个构造函数
console.log(VueRouter.prototype)------>是一个原型---->VueRouter的原型对象----->push就是在这里面
//先把VueRouter原型对象的push方法,先保存一份
let originPush = VueRouter.prototype.push

//重写push和replace方法
//第一个参数:告诉原来的push方法,你该往哪跳转(传递哪些参数)
//第二个参数是成功的回调,第三个是失败的回调
VueRouter.prototype.push = function (location, resolve, reject) {
    //这里面的this还是VueRouter的实例
    if (resolve && reject) {
        // originPush()这样调用是这不行的,上下文变成是window
        originPush.call(this, location, resolve, reject)//这行代码保证了上下文还是VueRouetr类的一个实例 $router
    } else {
        //缺少resolve或reject或都缺少,我们就手动传入两个回调函数,治根了,就不会报错
        originPush.call(this, location, () => { }, () => { })
    }
}
//同样的重写replace方法
//编程式导航有这个问题

call apply区别

相同点:都可以调用函数一次,都可以篡改函数上下文一次

不同点:call传递参数用逗号分隔,apply用数组传递

2 Home模块组件拆分

三级联动、轮播图与快报、猜你喜欢、商品展示

3 三级联动组件的完成

很多地方都使用(主页,搜索页,详情页),所以拆分为一个全局组件,优点就是只需注册一次,每个地方都可以使用

  • 创建全局组件TypeNav

  • 在路口文件main.js中注册全局组件,如下:

  • import TypeNav from '@/pages/Home/TypeNav'
    Vue.component('TypeNav', TypeNav) //第一个是注册组件的名字,第二个参数是要注册的组件
    
  • 在Home组件中使用一下 <TypeNav />

ctrl+h全局替换

4 完成其余静态组件

注意:HTML + CSS +图片资源

轮播图和快报一个组件

  • 创建静态组件(结构、样式、图片资源)ListContainer
  • 不需要注册为全局组件,在Home组件中引入和注册,再使用
//Home组件中
import ListContainer from "./ListContainer"; //引入
components: { ListContainer }, //注册组件
<ListContainer /> //使用

同理,今日推荐组件

拆分好Recommend组件,在Home中注册就可以

import Recommend from "./Recommend";
components: { ListContainer, Recommend },
<Recommend />

同理,商品排行组件Rank、猜你喜欢组件Like、楼层组件Floor

5 POSTMAN测试接口

使用最新服务器地址:http://gmall-h5-api.atguigu.cn

服务器返回的数据code字段是200表示服务器返回数据成功

整个项目,接口前缀都有/api字段

在这里插入图片描述

6 axios二次封装

向服务器发请求的方式有很多:XMLHttpRequest原生的构造函数、fecthJQaxios

6.1 为什么需要二次封装axios

目的:

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

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

项目中一般用src下的 API 文件夹放axios

首先安装axios
npm i axios

接口当中路径都带有/api,如:http:// xxx.xxx:8080/api
//对axios进行二次封装
//引入axios
import axios from 'axios'
//第一步:利用axios对象的方法create,去创建一个axios实例
//requests其实就是axios,只不过稍微配置一下
const requests = axios.create({
    //配置对象
    //基础路径,发请求的时候路径就会带上api,就不用一个一个去写了
    baseURL: "/api",
    //代表请求超时的时间5s
    timeout: 5000,
});
//请求拦截器:在发请求之前,请求拦截器可以检测到,在请求发出之前处理一些事情
requests.interceptors.request.use((config) => {
    //config:是一个配置对象,对象里面有个属性很重要,headers请求头
    return config
});
//响应拦截器:成功与失败回调
requests.interceptors.response.use((res) => {
    //成功回调函数:服务器返回相应数据后,响应拦截器可以检测到,做一些事情
    //比如:我们只需要data数据就可以,其他不用,那就返回res.data
    return res.data
}, (error) => {
    //失败的回调函数:也可以做一些事情,返回错误信息啊,或者终止promise链
    return Promise.reject(new Error('failure'))
});

export default requests

7 接口同一管理

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

项目较大:axios.get('xxx')

api文件下的index.js就是用来管理接口的

//对API接口进行统一管理
//发请求需要用到我们封装好的axios----requests,先引入
import requests from './request'

//三级联动的接口
//请求地址:/api/product/getBaseCategoryList    请求方式:GET   无参数
//对外暴露一个函数,其他组件需要发请求获取数据时,调用函数就可以
export const reqCategoryList = () => {
    //发请求:返回的是一个promise对象
    return requests({
        //不需要写/api了,之前在baseUrl中配置过
        url: '/product/getBaseCategoryList',
        method: 'get',
    })
}
//简写形式:
export const reqCategoryList = () => requests({ url: '/product/getBaseCategoryList', method: 'get', });
在mian.j入口文件中测试
//测试发送请求
import { reqCategoryList } from './api' //注意看看使用什么暴露,对应使用什么引入
reqCategoryList()
//会发现上面报404错误----跨域了----需要去配置代理服务器

7.1 跨域问题

什么是跨域:协议、域名、端口号不一致,就叫做跨域

前端项目本地服务器:http://localhost:8080/#/home

后台服务器:http://gmall-h5-api.atguigu.cn

解决跨域问题的方案:JSONPCROS、代理

//代理跨域---webpack提供了,就是vue.config.js文件
devServer: {
	proxy: {
		'/api': {
			target: 'http://gmall-h5-api.atguigu.cn'
		}
	}
}

//测试发送请求
import { reqCategoryList } from './api' //注意看看使用什么暴露,对应使用什么引入
reqCategoryList()
//现在就可以成功返回数据了

在这里插入图片描述

有一个报错需要注意一下

在这里插入图片描述

8 nprogress进度条的使用

npm i nprogress

start:是进度条的开始

done:是进度条的结束

在哪里调用?

在请求拦截器和响应拦截器中使用

进度条的样式我们可以在源样式文件中自行修改

//第一步:引入进度条
import nprogress from 'nprogress'
//start:进度条开始     done:进度条结束
//第三步:引入进度条样式才可以看见
import "nprogress/nprogress.css"
//第二步:
//在请求成功的拦截器里开始
nprogress.start();
//在响应拦截器的成功返回情况下
nprogress.done();

9 vuex状态管理库

9.1 vuex是什么

vuex是官方提供的一个插件:状态管理库,集中管理项目中组件共有的数据,达到共享资源的目的

注意:

不是所有项目都需要vuex,小的项目可以不用;如果项目很大,组件很多,数据很多,数据维护费力是,可以使用

本项目安装的是vuex@3.6.2

vuex的核心:statemutations actionsgettersmodules

9.2 vuex的基本使用

复习vuex

新建store文件夹–index.js

import Vue from 'vue'
import Vuex from 'vuex'
//使用插件
Vue.use(Vuex)

//state:仓库存储数据的地方
const state = {}
//actions:响应组件中用户的需求,可以书写业务逻辑
const actions = {}
//mutations:处理state的唯一手段
const mutations = {}
//getters:相当于计算属性,简化仓库数据,让要使用数据的组件更加方便的拿取
const getters = {}

//Vuex对象身上有一个store构造函数,需要暴露Store类一个实例
export default new Vuex.Store({
    state,
    actions,
    mutations,
    getters
})
引入了vuex,这样在创建vm实例的时候就多了一个全新配置项 store
在main.js中创建vm时传入store配置项
......
//引入store
import store from './store'
......

//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
     //注册仓库:每个组件的实例vc身上就会多一个$store属性
	store
})

9.3 vuex实现模块式开发

将大仓库拆分为小仓库

在大仓库中引入并注册就可以使用了

就是命名空间+模块化(可以看基础笔记

modules: {
    home,
    search
}

10 完成TypeNav三级联动展示数据业务

小仓库准备好,三级联动组件也准备好,那就在三级联动组件中,通知仓库发请求获取数据

第一步
//组件挂载完毕之后,向服务器发请求
mounted() {
  //通知vuex发请求,获取数据,存储于仓库当中
  this.$store.dispatch("home/categoryList");//注意!!!!!要告诉仓库派发到哪个模块小仓库,加上home/
},

第二步:对应的小仓库中要处理这次组件的派发请求
//这边我们向服务器发请求的操作,之前封装好了一个函数,在小仓库中导入然后调用就可以
//注意:axios返回的是promise,所以我们需要的是promise成功的结果
//注意:返回数据的时候看一下result.data是什么类型,这样我们就可以在state中准备好相应的空数据
//home小仓库中:
state: {
    //3:state中的数据默认初始值不可以瞎写,根据返回的data来初始化
    categoryList: [],
},
actions: {
    //1:通过API里面的接口函数调用,向服务器发请求,获取服务器的数据
    async categoryList(context) {
        const result = await reqCategoryList();
        //成功返回的话我们要修改仓库中的数据了
        if (result.code == 200) {
            context.commit('CATEGORYLIST', result.data)
        }
    }
},
mutations: {
    CATEGORYLIST(state, categoryList) {
        //2:修改state中的categoryList---事先准备好空的categoryList
        state.categoryList = categoryList
    }
},
//ok现在仓库拿到数据了,接下来就是在组件从仓库拿数据,然后展示即可
//三级联动组件中:我自己用的命名空间的写法,老师没有开命名空间,用的是对象的写法,vuex提供了右侧的一个函数
computed: {
  ...mapState("home", ["categoryList"]),
},
老师的写法:
computed: {
  ...mapState({
  	//右侧是一个vuex提供的函数,使用计算属性时,会执行
    //注入一个参数state,其实即为大仓库中的数据(就是小仓库啦)
    categoryList:sate=>state.home.categoryList
  }),
},
最后展示数据
<div class="item bo" v-for="c1 in categoryList" :key="c1.categoryId">
  <h3>
    <a href="">{{ c1.categoryName }}</a>
  </h3>
  <div class="item-list clearfix">
    <div
      class="subitem"
      v-for="c2 in c1.categoryChild"
      :key="c2.categoryId"
    >
      <dl class="fore">
        <dt>
          <a href="">{{ c2.categoryName }}</a>
        </dt>
        <dd>
          <em v-for="c3 in c2.categoryChild" :key="c3.categoryId">
            <a href="">{{ c3.categoryName }}</a>
          </em>
        </dd>
      </dl>
    </div>
  </div>
</div>

今日的错误点

  • 二次封装axios的时候create单词写错

  • 二次封装axios的时候response单词写错 导致页面丢失

  • 出现以下👇的报错不是我的锅!!!查看了半天代码,是服务器炸了!!!!
    在这里插入图片描述

  • 写函数时,嵌套写了,看走眼呜呜呜,还有箭头函数的简写可以复习一下

  • 看到下面这个的时候,我内心是无比快乐的

  • 在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值