01 vue-router 路由
1.1 重定向
- 配置路由时,处理
/
,进行重定向
router/index.js 文件
export default new VueRouter({
// 配置路由
routes: [
// 重定向,项目跑起来时,访问/,立马跳转到home页面
{
path: '/',
redirect: '/home'
}
]
})
1.2 $router 和 $route
$router
:一般进行编程式路由导航【push、replace】- 是 VueRouter 的一个对象,通过
Vue.use(VueRouter)
和 VueRouter 构造函数得到一个 router 的实例对象,这个对象中是一个全局的对象,包含了所有的路由包含了许多关键的对象和属性
- 是 VueRouter 的一个对象,通过
$route
:一般获取路由信息【路径、query、params 等等】- 是一个跳转的路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name、path、params、query 等
1.3 路由的跳转
- 声明式路由导航 router-link,务必有 to 属性,可以实现路由的跳转
- 编程式路由导航,利用组件实例的
$router.push
或$router.replace
- 声明式路由导航能做的编程式路由导航都能做,编程式路由导航除了可以进行路由跳转,还可以做一些其他的业务逻辑
1.4 路由元信息 meta
配置路由时添加元信息
meta: { show: true }
配合v-show/v-if
控制组件是否显示- 【其他用途】待添加
router/index.js 文件
export default new VueRouter({
// 配置路由
routes: [
{
path: '/home',
component: Home,
// 路由元信息
meta: {
show: true
}
}
]
})
1.5 路由参数
- params 参数:属于路径的一部分,在配置路由时需要占位
- query 参数:不属于路径的一部分,类似 ajax 中的 queryString
// 编程式路由导航
// 第一种:字符串形式
this.$router.push("/search/" + this.keyword + "?k=" +this.keyword.toUpperCase())
// 第二种:模板字符串
this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`)
// 第三种:对象
this.$router.push({
name: "search",
params:{
keyword:this.keyword
},
query:{
k:this.keyword.toUpperCase()
}
})
1.6 路由跳转传参时 params 参数只能与 name配合使用
- 采用对象式写法时 params 参数必须与 name 配合,不能与 path 配合!!!
1.7 如何指定 params 参数可传可不传
- 比如:配置路由时已经占位了,但是路由跳转时不传递,此时路径会出问题
- e.g:
http://localhost:8080/?k=aaa
正确路径为http://localhost:8080/search?k=aaa
- 解决办法:占位时后面加一个
?
- e.g:
router/index.js 文件
export default new VueRouter({
// 配置路由
routes: [
{
// 指定 params 参数可传可不传
path: '/search/:keyword?',
component: Search,
name: 'search',
meta: {
show: true
}
}
]
})
1.8 params 参数可传可不传,如果是空串,如何解决
- e.g:
http://localhost:8080/?k=aaa
正确路径为http://localhost:8080/search?k=aaa
- 解决办法:使用 undefined 解决
this.$router.push({
name: "search",
params:{
keyword: '' || undefined
},
query:{
k:this.keyword.toUpperCase()
}
})
1.9 路由组件传递 props 数据
router/index.js 文件
export default new VueRouter({
// 配置路由
routes: [
{
path: '/search/:keyword?',
component: Search,
name: 'search',
meta: {
show: true
},
// 布尔值写法:只能传递 params 参数
props: true,
// 对象写法:额外给路由组件传递一些 props
props: { a:1,b:2 },
// 函数写法:可以把params参数,query参数,通过props传递给路由组件
props:($route) => ({ keyword: $route.params.keyword,k: $route.query.k })
}
]
})
1.10 重写 push | replace 方法
- 解决搜索按钮重复点击跳转路由时,报错:
Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/search/sss?k=SSS".
,通过给 push、replace 方法传递相应的成功、失败的回调函数可以捕获到当前错误,可以解决 - push() 和 replace() 返回的是一个 Promise 对象
// 先把VueRouter原型对象的push保存一份
let originPush = VueRouter.prototype.push
// 重写 push
/**
*
* @param {*} location 告诉原来的push方法往哪里传参
* @param {*} resolve 成功的回调
* @param {*} reject 失败的回调
*/
VueRouter.prototype.push = function(location, resolve, reject){
if(resolve && reject){
originPush.call(this, location, resolve, reject)
}else{
originPush.call(this, location, () => {}, () => {})
}
}
// 先把VueRouter原型对象的replace保存一份
let originReplace = VueRouter.prototype.replace
// 重写 replace
/**
*
* @param {*} location 告诉原来的replace方法往哪里传参
* @param {*} resolve 成功的回调
* @param {*} reject 失败的回调
*/
VueRouter.prototype.replace = function(location, resolve, reject){
if(resolve && reject){
originReplace.call(this, location, resolve, reject)
}else{
originReplace.call(this, location, () => {}, () => {})
}
}
02 设置路径别名 @
代表 src
jsconfig.json 文件夹
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
],
"exclude": ["node_modules", "dist"]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}
03 注册全局组件
main.js
文件里注册,使用时不需要再 import 引入
main.js 文件
// 三级联动组件 --- 注册为全局组件
import TypeNav from '@/pages/Home/TypeNav'
// 注册全局组件
// 第一个参数:全局组件的名字,第二个参数:哪个组件
Vue.component(TypeNav.name, TypeNav)
04 请求相关
4.1 axios 二次封装
- 请求拦截器和响应拦截器:在发请求之前和服务器数据返回以后处理一些业务
api/request.js 文件
// 对axios进行二次封装
import axios from "axios"
// 1.利用axios对象的方法create创建一个axios实例
// 2.requests就是axios,进行配置
const requests = axios.create({
// 配置对象
// 基础路径
baseURL: '/api',
// 超时时间 5s
timeout: 5000,
})
// 请求拦截器
requests.interceptors.request.use((config) => {
// config:配置对象,对象里面有一个属性很重要,header请求头
return config
})
requests.interceptors.response.use((res) => {
// 成功的回调
return res.data
}, (error) => {
console.log(error.message)
return new Promise(() => {})
})
// 对外暴露
export default requests
4.2 接口统一管理
- 项目很小:在组件的生命周期函数中发请求
- 项目大:
axios.get('xxx')
api/index.js 文件
// 所有api进行统一管理
import requests from './request';
// 三级联动接口
// /api/product/getBaseCategoryList GET 无参数
export const reqCategoryList = () => {
// 发请求:axios发请求返回Promise对象
return requests({
url: '/product/getBaseCategoryList',
method: 'GET'
})
}
05 nprogress 插件
- 控制进度条
nProgress.start()
:进度条开始nProgress.done()
:进度条结束- 进入
nprogress/nprogress.css
在#nprogress .bar{ background: #ff0 }
里可修改进度条颜色
npm i --save nprogress
api/request.js 文件
// 对axios进行二次封装
import axios from "axios"
// 引入进度条插件
import nProgress from "nprogress"
// star:进度条开始,done:进度条结束
// 引入进度条样式
import 'nprogress/nprogress.css'
// 1.利用axios对象的方法create创建一个axios实例
// 2.requests就是axios,进行配置
const requests = axios.create({
// 配置对象
// 基础路径
baseURL: '/api',
// 超时时间 5s
timeout: 5000,
})
// 请求拦截器
requests.interceptors.request.use((config) => {
// 进度条开始
nProgress.start()
// config:配置对象,对象里面有一个属性很重要,header请求头
return config
})
requests.interceptors.response.use((res) => {
// 进度条结束
nProgress.done()
// 成功的回调
return res.data
}, (error) => {
console.log(error.message)
return new Promise(() => {})
})
// 对外暴露
export default requests
06 vuex
6.1 模块开发
src/store/home/index
// home模块小仓库
// 仓库存储数据的地方
const state = {
}
// 修改state的唯一手段
const mutations = {
}
// 书写业务逻辑,也可以处理异步,但不能修改state
const action = {
}
// 类似计算属性,用于简化仓库数据,让组件获取仓库的数据更方便
const getters = {
}
export default {
state,
mutations,
action,
getters
}
src/store/search/index
// search模块小仓库
// 仓库存储数据的地方
const state = {
}
// 修改state的唯一手段
const mutations = {
}
// 书写业务逻辑,也可以处理异步,但不能修改state
const action = {
}
// 类似计算属性,用于简化仓库数据,让组件获取仓库的数据更方便
const getters = {
}
export default {
state,
mutations,
action,
getters
}
src/store/index
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 引入小仓库
import home from './home'
import search from './search'
export default new Vuex.Store({
modules: {
home,
search
}
})
6.2 未命名模块空间
computed: {
...mapState({
// 右侧需要一个函数,当使用这个计算属性的时候,右侧函数就会立即执行一次
// 注入一个参数state,其实为大仓库中的数据
categoryList: state => state.home.categoryList
})
}
dex**
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 引入小仓库
import home from './home'
import search from './search'
export default new Vuex.Store({
modules: {
home,
search
}
})