day2
1:编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的错误警告?
路由跳转有两种形式:声明式导航,编程式导航
声明式导航没有这类问题的,因为vue-router底层已经处理好了
1.1为什么编程导航进行路由跳转的时候,就有这种警告错误那?
"vue-router":"^3.5.3":最新的vue-router引入promise
1.2通过给push方法传递相应的成功,失败的回调函数,可以捕获到当前的错误,可以解决,
1.3通过底部的代码,可以解决错误
this.$router.push({name:'search',params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}},
//成功的回调
()=>{},
//错误的回调
(error)=>{})
这种写法:治标不治本,将来在别的组件当中push|replace,编程式导航还是有类似的错误
1.4可以通过重写push|replace方法解决
this:当前组件实例(search)
this.$router属性是一个对象:当前的这个属性,属性值是VueRouter类的一个实例,当在入口文件注册路由的时候,给组件实例添加的$router|$route属性
push:VueRouter类的一个实例
function VueRouter(){}
//原型对象的方法
VueRouter.prototype.push = function(){
//函数的上下文为VueRouter类的一个实例
}
let $router = new VueRouter()
$router.push(xxx)
// /router/index.js
// 重写push|和replace方法
// 先把VueRouter原型对象的push方法,先保存一份
let originPush = VueRouter.prototype.push
let originReplace = VueRouter.prototype.replace
// 重写push|replace方法
// 第一个参数:告诉原来push方法,你往哪里跳转(传递哪些参数)
// 第二个参数:成功的回调
// 第三个参数:失败的回调
// call|apply区别:
// 相同点,都可以调用函数一次,都可以篡改函数的上下文一次
// 不同点 call与apply传递参数:call传递参数用逗号隔开,apply方法执行,传递数组
VueRouter.prototype.push = function (location, resolve, reject) {
if (resolve && reject) {
originPush.call(this, location, resolve, reject)
} else {
originPush.call(this, location, () => { }, () => { })
}
}
VueRouter.prototype.replace= function(location,resolve,reject){
if (resolve && reject) {
originReplace.call(this, location, resolve, reject)
} else {
originReplace.call(this, location, () => { }, () => { })
}
}
call() 方法是预定义的 JavaScript 方法。
它可以用来调用所有者对象作为参数的方法。
通过 call(),您能够使用属于另一个对象的方法。
本例调用 person 的 fullName 方法,并用于 person1:
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates",
}
var person2 = {
firstName:"Steve",
lastName: "Jobs",
}
person.fullName.call(person1); // 将返回 "Bill Gates"
2.Home模块组件拆分
--先把静态页面完成
--拆分出静态组件
--获取服务器数据
--动态的业务完成即可
把静态页面组件建立在Home文件夹下
3.三级联动组件完成
-由于三级联动,在Home、Search、Detail,把三级联动注册为全局组件
好处:只需要注册一次,就可以在项目任意地方使用(typeNav)为三级联动
4.完成其他的静态组件
html + CSS +图片资源 --信息 【结构 组件信息】
5.通过postman测试接口
--经过postman工具测试,接口是没有问题的
--如果服务器返回的数据code字段200 , 代表服务器返回数据成功
--整个项目,接口前缀都有/api字样
6.axios二次封装
XMLhttpRequest、fetch jq、axios
6.1 为什么需要进行二次封装axios?
请求拦截器、相应拦截器、请求拦截器,可以再发请求之前可以处理一些业务,相应拦截器,当服务器数据返回以后,可以处理一些事情
6.2在项目当中经常出现api【axios请求】
接口当中:路径都带有/api
baseURL:"/api"
http://xxx.xxx:8080/api
请求拦截器的配置。在api文件夹下创建request.js
// 对于axios进行二次封装
import axios from 'axios'
import nprogress from 'nprogress'
// 引入进度条的样式
import 'nprogress/nprogress.css'
// start:进度条开始 done:进度条结束
// 1:利用axios对象的方法create,去创建一个axios实例
// 2:request就是axios,只不过稍微配置以下
const requests = axios.create({
// 配置路径
// 基础路径,发送请求的时候,路径当中会出现api
baseURL: "/api",
// 代表请求超时的时间5s
timeout: 5000,
})
// 请求拦截器:发送求求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => {
// config:配置对象,对象里面有一个属性很重要,header请求头
// 进度条开始动
nprogress.start();
return config;
})
// 响应拦截器
requests.interceptors.response.use((res) => {
// 成功的回调函数,服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情
// 进度条结束
nprogress.done();
return res.data;
}, (error) => {
// 服务器响应失败的回调函数
return Promise.reject(new Error('faile'))
})
// 对外暴露
export default requests
7.接口统一管理业务
项目很小:完全可以在组件的生命周期函数中发请求
一般将所有接口请求地址都写到api文件夹下
7.1 跨域问题
什么是跨域:协议,域名,端口号不同请求,称之为跨域
http://localhost:8080/#/home --前端项目本地服务器
http://39/98.123.211 --后台服务器
解决跨域的方法
JSONP CROS 代理服务器
这里我们使用的是代理服务器的方法,是webpack中的 devServer.proxy
在vue.config.js文件中添加
// 代理跨域
devServer: {
proxy: {
"/api": {
target: "http://39.98.123.211",
// pathRewrite: { "^/api": "" } 这里是地址重写
}
}
}
8.nprogress进度条的使用
安装 npm install --save nprogress
进度条在拦截器处使用
start:进度条开始
done:进度条结束
在请求拦截器处使用
nprogress.start();
在响应拦截器处使用
nprogress.done()
进度条的颜色可以修改的,需要修改css样式
9:vuex状态管理库
9.1vuex是什么
vuex是官方提供一个插件,状态管理库,集中式管理项目中组件共用的数据
切记,并不是全部项目都需要vuex 如果项目很小,完全不需要vuex 如果项目很大,组件很多,数据很多,数据维护很费劲,Vuex
state
mutations
acitons
getters
modules
这里由于cli版本的问题不能安装最新的vuex 只能安装3.x版本的
9.2vuex基本使用
这个是Vuex下的index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 需要使用插件一次
Vue.use(Vuex);
// state:仓库存储数据的地方
// const state = {}
// // mutations:修改state的唯一手段
// const mutations = {}
// // action:处理action,可以书写自己的业务逻辑,也可以处理异步
// const actions = {}
// // getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
// const getters = {}
// // 对外暴露Store类的一个实例
export default new Vuex.Store({
state,
mutations,
actions,
getters
});
9.3vuex实现模块化开发
如果项目过大,组件过多,接口也很多,数据也很多,可以让vuex实现模块化
创建Home仓库下的index.js Search模块下的仓库和home模块的仓库初始哈代码相同
// home模块的小仓库
const state = {
}
const mutations = {
const actions = {
}
const getters = {
}
export default {
state, mutations, actions, getters
}
import Vue from 'vue'
import Vuex from 'vuex'
// 需要使用插件一次
Vue.use(Vuex);
// 引入小仓库
import home from './home';
import search from './search';
// state:仓库存储数据的地方
// const state = {}
// // mutations:修改state的唯一手段
// const mutations = {}
// // action:处理action,可以书写自己的业务逻辑,也可以处理异步
// const actions = {}
// // getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
// const getters = {}
// // 对外暴露Store类的一个实例
export default new Vuex.Store({
// state,
// mutations,
// actions,
// getters
// 实现仓库模块化开发存储数据
modules: {
home, search
}
});
通过api下index.js写好的调用接口的函数获取数据,并通过store仓库储存起来
// home模块的小仓库
import { reqCategoryList } from "@/api"
const state = {
//state中数据默认初始值别瞎写,服务器返回的是对象,起始值就是对象,服务器返回的是数组,起始值就是数组
categoryList: []
}
const mutations = {
CATEGORYLIST(state, categoryList) {
state.categoryList = categoryList
}
}
const actions = {
// 通过api里面的接口函数调用,向服务器发请求,获取服务器的数据
async categoryList({ commit }) {
let result = await reqCategoryList();
if (result.code == 200) {
commit("CATEGORYLIST", result.data)
}
}
}
const getters = {
}
export default {
state, mutations, actions, getters
}
再通过typeNav下的mounted钩子函数,将数据导入
通过this.$store.dispatch方法调用store仓库中的action中的categoryList
因为这里如果只用categorylist函数的化获取的是一个promise对象,获取不了数据,所以通过
async await 获取数据
再通过commit提交到mutations里面再修改state里面的数据
如果这里整不懂vuex的可以看我之前的文章中vuex基础的学习
这里唯一难理解的就是commit的解析,这里用了es6的解析
原本应该是
add(context){
context.commit('',data)
}
10:完成TypeNav三级联动展示数据业务
[
{
id:1
name:'电子书'
child:[
{id:2,name:"喜羊羊",child:[]}
]
},
{},
{}
]