通过ui页面分析
Footer组件 在Home Search显示Footer组件 而在登录 注册页面是隐藏的
6 Footer组件显示与隐藏 v-if(操作dom节点 耗性能) 或v-show(样式控制) 需要的是布尔值 true和false
----可通过判断路由是哪个 是否显示与隐藏(不推荐 如果组件过多 此方法冗余)
----推荐 router插件提供的 meta配置项 也就是路由元信息
const routes = [{
//显示的为true 隐藏的为false
meta:{show:true}
},
{
path:'/search/:keyword',
name:'search',
component:Search,
meta:{show:true},
props:true,
},
]
在根组件App.vue中 所使用的Footer非路由组件 通过v-show=“$route.meta.show” 判断是否显示与隐藏
8.1 路由的跳转 有几种方式
----声明式导航 router-link (务必有to属性) 往哪跳
----编程式导航 用的是组件实例的$router.push|replace方法 除了跳转 还可以收集数据 发请求 功能全
8.2 路由传参 有几种方式
----params参数 属于路径当中的一部分 注意 在配置路由时 需要先占位
----query参数 不属于路径当中的一部分 类似于ajax中的queryString /home?k=v&k=v 不用占位
----(传参)使用场景 在home页 把收集到的 搜索关键字 跳转到搜索页并带给它 告诉是哪个关键字
/components/Header/index.vue
收集表单数据 搜索关键字 数据双向绑定 v-model
自身数据存储
data() {
return {
keyword:'',
}
},
对应的input 数据绑定 v-model=‘keyword’
<input type="text" id="autocomplete" class="input-error input-xxlarge" v-model="keyword"/>
对应回调中
//尝试编程式导航 搜索页跳转的回调
goSearch(){
//路由传参 几种形式
//第一种 字符串形式 params参数 路径的一部分 注意 配置路由时先占位 比如是abc此时 url中会出现关键字
//query参数 是以?开头 k=v的形式
this.$router.push('/search/' + this.keyword + "?k=" +this.keyword.toUpperCase());
//第二种 模板字符串
this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`)
//第三种 对象写法(较常用) 需在 router/index.js中 对应的配置项中 添加name属性 name:'search' 对象中使用name关键字 而不是path
this.$router.push({name:'search',params:{abc:this.keyword},query:{k:this.keyword.toUpperCase()}})
}
9.路由传参相关面试题
----9.1路由传参(对象写法) path是否可以结合params参数一起使用? 答:不能 如下编写 不能跳转并报错
this.$router.push({path:'search',params:{abc:this.keyword},query:{k:this.keyword.toUpperCase()}})
**----9.2如何指定params参数可传可不传? 现在 路由已占位叫abc 如下编写 没有传params参数 路径会有问题
//只有query参数 当前页的路径名也会丢失 如何指定可传 在占位后加一个? 理解为正则表达式的 0或1
**
this.$router.push({name:'search',query:{k:this.keyword }})
----9.3params参数可以传递也可以不传递 但是 如果传递是空串 如何解决?
问题1.路径依然是丢失当前字符
**可解决 使用||undefined **
this.$router.push({name:'search',params:{abc:''||undefined},query:{k:this.keyword.toUpperCase()})
----9.4路由组件能不能传递props数据? 答 可以 (三种写法) 较少用 因为props通常在组件间通信使用
第一种 布尔值写法 router/index.js props:true, 注意只有 带有params参数 的组件
另外在 /Search/index.vue中 接收 props:[‘abc’],
const routes = [{
//显示的为true 隐藏的为false
meta:{show:true} //路由元 控制footer组件是否显示
},
{
path:'/search/:abc?',
name:'search',
component:Search,
meta:{show:true},
//----9.4路由组件能不能传递props数据? 可以
// 第一种 布尔值写法 注意只有 params参数
props:true,
// 第二种 对象写法 可以额外的给路由组件传递props数据 当然 需要相应组件接收 以上都不常用
// props:{a:1,b:2}
// 函数写法 可以把params query参数 通过props传递给路由组件
// props:($route)=>{
// return {abc:$route.params.abc,k:$route.query.k}
// }
},
]
9.5.编程式导航路由跳转到当前路由(参数不变) 多次执行会抛出NavigationDuplicated的警告?
–声明式导航没有这类问题 因为 vue-router底层已处理
–1.1.编程式导航会有这个问题 因为从3.5.3版本 vue-router 引入了 promise 有成功和失败回调
–1.2.通过给push方法传递相应的成功 失败的回调函数 可以捕获到当前错误
//重写 VueRouter.prototype 的 push|replace 方法可解决
/router/index.js
//先把VueRouter原型对象的push 先保存一份
let originPush = VueRouter.prototype.push;
//重写 VueRouter.prototype 的 push|replace 方法
//第一个参数 告诉原型对象的push方法 往哪跳转(传递哪些参数)
VueRouter.prototype.push = function(location,resolve,reject){
if(resolve && reject){
//call || apply区别
//相同点 都可以调用函数一次 并且可以篡改函数的上下文一次
//不同点 call与apply传递参数不同 call传递参数用逗号隔开 而apply方法 传递数组
originPush.call(this,location,resolve,reject);
}else{
originPush.call(this,location,()=>{},()=>{});
}
}
2.Home组件模块拆分
----先把静态页面完成
----拆分出静态组件
----获取服务器的数据动态展示
3.三级联动组件完成
----由于三级联动 在Home Search Detail 都有使用 注册为全局组件 方便使用
----/pages/Home/TypeNav/index.vue 编写静态组件
----入口文件 main.js中 注册为全局组件
----先引入 import TypeNav from ‘@/pages/Home/TypeNav’
----再注册 Vue.component(TypeNav.name,TypeNav)
----/Home/index.vue 标签形式使用
4.在/Home/下完成其余静态组件
Html + CSS + 图片资源
5.POSTMAN测试接口
POSTMAN测试接口工具的使用
----返回的是code=200 代表成功 反之失败
----整个项目 接口前缀都有/api字样
6.axios 二次封装 其他方式 XMLHttpRequest | fetch | JQ axios src/api/index.js
----6.1 二次封装原因?
------请求拦截器 响应拦截器
------请求拦截器:可在发请求之前处理一些业务
------响应拦截器:当服务器返回数据以后 可以处理一些业务
----6.2在项目中经常出现api文件夹(请求相关)
----6.3 src/api/index.js
//引入axios库
import axios from "axios";
//request接收axios实例 进行配置
const requests = axios.create({
//配置对象 基本路径 发请求时 路径当中会出现api
baseURL:"/api",
timeout:5000,
});
//请求拦截器:在发请求之前 拦截器可以监测到 发出去之前做一些业务
requests.interceptors.request.use((config)=>{
//config:配置对象参数 里面有一个属性很重要,headers请求头
return config;
});
//响应拦截器:服务器相应数据返回后 拦截器可以监测到 可以做一些业务
requests.interceptors.response.use((res)=>{
return res.data;
},(error)=>{
return Promise.reject(new Error('faile'))
})
//对外暴露
export default requests;
----场景一 项目很小 接口就几个 完全可以在组件的生命周期函数中发请求
----项目复杂 接口多 有的接口在不同组件都有使用 后期接口一旦变化 使用过这个接口的都需改 所以统一管理较方便
7.接口统一管理
/api/+index.js 此文件引入封装好的axios 调用requests 可以发起各个接口请求
----7.1跨域问题
----协议 域名 端口号 不同 配置代理跨域方案
----/src/vue.config.js中配置
devServer:{
proxy:{
'/api':{
target:'url',
// pathRewrite:{'^/api':''},//路径重写
}
}
}
//切记配置文件修改之后 项目需要重新启动
8.请求进度条 nprogress插件的使用
----8.1 项目安装nprogress插件
cnpm i --save nprogress
/api/index.js 引入模块和对应的样式
import nprogress from ‘nprogress’;
9.vuex状态管理库
----9.1 它是什么 作用?
----首先 它是官方提供的一个插件 状态管理库 集中式管理项目中组件共用的数据
----场景 项目复杂 组件多 数据维护繁琐
----几大核心
state
mutations
actions
getters
modules
----既然是为解决管理各个组件的数据的插件 模块化优势支持
----既然是插件了 首先项目中安装
cnpm i --save vuex@3.6.2
----9.2vuex基本使用
/src/+store/+index.js
----引入 import Vue from “vue”
-----import Vuex from “vuex”;
//先use一次 Vuex的Store方法 是一个构造函数可以去初始化仓库
Vue.use(Vuex)
//state:仓库存储数据的地方
const state = {};
//mutations:修改state的唯一手段
const mutations = {};
//actions:处理actions 可以书写业务逻辑 处理异步
const actions = {};
//getters:理解计算属性 简化仓库数据 让组件获取仓库的数据更加方便
const getter = {};
//对外暴露Stroe类的一个实例
//此种方式是都放在一个仓库(不推荐)
export default new Vuex.Store({
state,
mutations,
actions,
getters,
})
----9.3vuex实现模块化开发方式
----把一个仓库 拆分成若干小仓库 对应若干组件 这样仓库存储的是 对应组件的数据 新建对应的模块文件 例如
store/+home/+index.js
const state = {};
const mutations = {};
const actions = {};
const getters = {};
export default{
state,
mutations,
actions,
getters,
}
在/store/index.js //分别引入小仓库
import home from './home';
import search from './search';
//对外暴露Stroe类的一个实例
export default new Vuex.Store({
//模块式开发方式存储
modules: {
home,
search,
}
})
10.完成TypeNav三级联动展示数据业务
----全局组件TypeNav放在components文件中
----10.1对应组件派发actions 通知vuex调用api发请求
/TypeNav/index.vue 派发actions
//挂载生命周期函数
mounted() {
//通知Vuex发请求 获取数据 存储于仓库中
this.$store.dispatch('categoryList');
},
/store/home/index.js 处理actions 进行三连环 拿到数据 修改state 存数据
//home模块的小仓库
//引入封装好的请求文件
import { reqCategoryList } from "@/api";
//state:仓库存储数据的地方
const state = {
//state中默认数据初始值类型是根据服务器返回的类型决定的
categoryList:[],
};
//mutations:修改state的唯一手段
const mutations = {
CATEGORYLIST(state,categoryList){
state.categoryList = categoryList;
}
};
//actions:处理actions 可以书写业务逻辑 处理异步
const actions = {
//通过API里面的接口函数调用 向服务器发请求 获取服务器数据
async categoryList({commit}){
let result = await reqCategoryList();
// console.log(result);// Promise
if(result.code == 200){
commit('CATEGORYLIST',result.data)
}
}
};
commit提交mutations存数据 此时注意 提交 两个参数 第一个参数 提交的名字 第二个 提交的数据
----接下来就是组件拿到仓库的数据 展示即可
----使用mapState辅助函数 映射为组件身上的一个属性 (如果不是简写形式 务必要有 return)
/TypeNav/index.vue 展示 引入辅助函数mapstate
import { mapState } from 'vuex';
computed: {
...mapState({
//右侧需要的是一个函数
categoryList:(state) => {
// console.log(state);
return state.home.categoryList;
}
})
}
对应标签使用v-for指令 渲染数据
<div class="item" v-for="(c1,index) in categoryList" :key="c1.categoryId">
<h3>
<a href="">{{c1.categoryName}}a>
h3>
<div class="item-list clearfix">
<div class="subitem" v-for="(c2,index) in c1.categoryChild" :key="c2.categoryId">
<dl class="fore">
<dt>
<a href="">{{c2.categoryName}}a>
dt>
<dd>
<em v-for="(c3,index) in c2.categoryChild" :key="c3.categoryId">
<a href="">{{c3.categoryName}}a>
em>
dd>
dl>
div>
div>
div>