一、路由传递参数相关面试题
1. 路由传递参数(对象写法)path是否可以结合params参数一起使用?
答:不能,路由跳转传参时,对象的写法命名路由可以是name或path形式,但需要传递params参数时,不能以path这种写法。
2. 如何指定params参数可传可不传?
答:配置路由的时候,占位了params参数(path: '/search/:keyword',)但是路由跳转的时候却不传递,路径会出现问题。解决方法:配置路由时params参数占位后面加了问号path: '/search/:keyword?',代表这个params参数可传可不传。
3. params参数可以传递也可以不传递,但如果传递的是空串,如何解决?
params: {
keyword: "",
},
路径会出现问题
答:使用undefined解决,params参数可以传递,也可以不传递(空的字符串)
this.$router.push({
name: "search",
params: {
keyword: "" || undefined,
},
query: {
k: this.keyword.toUpperCase(),
},
});
4. 路由组件能不能传递props数据?(很少使用)
答:可以,有3种写法
a. 布尔值写法:配置路由时加上 props: true, 这种写法只能传递params参数
b. 对象写法:配置路由时加上 props: { a: 1, b: 2 }, 额外给路由组件传递一些props
c. 函数写法:配置路由时加上如下代码,可以把params参数、query参数,通过props传递给路由组件
props: ($route) => {
return {
keyword: $route.params.keyword,
k: $route.query.k
}
}
*一般路由传参直接通过 $route.params.keyword 形式就可以获取,而不需要通过props传递
二、问题解决
1. 编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误?
路由跳转有两种形式:声明式导航(router-link)、编程式导航(函数)
声明式导航没有这类问题,因为vue-router底层已经处理好了
为什么编程式导航进行路由跳转时,会有这种警告错误?
最新的vue-router引入了promise
push方法相当于
function push(){ return new Promise((resolve, reject)=>{}) }
promise需要传递成功或失败的回调,才能捕获异常
如何处理:在调用push时,除了传递往哪跳的参数,还要传递相应的成功的、失败的回调函数,就可以捕获到当前的错误。但这种写法治标不治本
治本:重写push和replace
// 先把VueRouter原型对象的push和replace保存一份
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace;
// 重写push与replace
// 第一个参数:location,告诉原来的push方法,往哪里跳转,以及传递哪些参数
// 第二个参数:成功的回调
// 第二个参数:失败的回调
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和apply
相同点:都可以调用函数一次,都可以篡改函数上下文一次
不同的:call传递参数用逗号隔开,apply用数组传递参数
三、跨域问题可以通过代理服务器解决
跨域的解决方案:JSONP、CROS、代理
在vue.config.js文件中配置代理跨域
// 代理跨域
devServer: {
proxy: {
'/api': {
target: 'http://gmall-h5-api.atguigu.cn',
// pathRewrite: { '^/api': '' }, //重写路径,让所有的路径都带/api
}
}
}
前端项目发送请求时如果路径中带有/api,代理服务器就会转发请求,找真实的服务器要数据,返回到前端项目展示
此时axios中的baseURL不需要写服务器ip地址
四、nprogress进度条插件
项目中出现发请求,进度条就会往前跑,当服务器数据返回成功,进度条就会消失
nprogress对象中,start()方法代表进度条开始动,done()方法代表进度条结束
可以在网络请求中引入import nprogress from 'nprogress',并引入样式import 'nprogress/nprogress.css';
在请求拦截器调用开始方法,响应拦截器调用结束方法
进度条颜色可通过样式修改
五、防抖与节流
防抖:前面所有的触发都被取消,最后一次执行在规定时间之后才会触发。即如果连续快速触发,只会执行最后一次。
节流:第一次触发回调后,在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会再次触发回调,把频繁触发变为少量触发。即每次触发后禁用一段时间。
lodash插件:里面封装了函数的防抖与节流的业务(包含闭包、延迟器的知识)
lodash函数库对外暴露的是一个_函数(类似jQuery暴露$函数)
// 防抖
const input = document.querySelector('input');
input.oninput = _.debounce(function () {
console.log('发送请求')
}, 1000);
// 节流
const span = document.querySelector('span');
const btn = document.querySelector('button');
let count = 0;
btn.onclick = _.throttle(function () {
count++;
span.innerHTML = count;
}, 1000);
throttle的回调函数不要用箭头函数,可能出现上下文this问题
六、路由跳转
(1)声明式导航:router-link (2)编程式导航:push/replace
使用router-link出现卡顿现象:因为router-link是一个组件,当服务器数据返回后,如果循环出大量的router-link组件(组件要创建组件实例,还要将虚拟DOM转化为真实DOM),在创建组件实例时,一瞬间创建过多很耗内存,因此出现卡顿。
最好的解决方案:编程式导航+事件委派(把所有子节点的事件委派给父节点)-----------案例:三级联动组件 vue-shangpinhui > src > components > TypeNav
七、过渡:<transition>
元素作为单个元素/组件的过渡效果
Vue 提供了 transition
的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用
v-if
) - 条件展示 (使用
v-show
) - 动态组件
- 组件根节点
前提:组件或元素务必要有v-if或v-show指令才可以进行过渡动画
<!-- 过渡动画 -->
<transition name="sort">
<div class="sort" v-show="show">...
</div>
</transition>
transition标签不加name属性时,通过.v-enter、.v-enter-to、.v-enter-ative等来写样式;
如果加了name属性,如name='fade',则通过 .fade-enter、.fade-leave-to等写样式。
name 属性是用来自定义过渡类名前缀,因为不写name如果有多个动画就分不清了。
<div id="example-1">
<button @click="show = !show">
Toggle render
</button>
<transition name="slide-fade">
<p v-if="show">hello</p>
</transition>
</div>
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
八、mock数据
需要用到mockjs插件
mock数据不会和服务器进行任何通信,请求会被浏览器拦截
使用步骤:
1. 在项目的src文件夹中创建一个mock文件夹
2. 准备JSON数据
3. 把mock数据需要的图片放置在public文件夹中(public文件夹在打包时会把相应的资源原封不动地打包到dist文件夹中)
4. 开始mock虚拟的数据,通过mockjs模块实现:创建mockServe.js,通过mockjs插件实现模拟数据
// 先引入mockjs模块
import Mock from 'mockjs';
// 把JSON数据格式引入进来
import banner from './banner.json';
import floor from './floor.json';
// mock数据:Mock对象上的mock方法
// 第一个参数:请求的地址
// 第二个参数:请求的数据
Mock.mock('/mock/banner', { code: 200, data: banner });//模拟轮播图数据
Mock.mock('/mock/floor', { code: 200, data: floor });
5. 把mockServe.js在入口文件中引入(至少执行一次,才能模拟数据)
// 引入mockServe.js-------用于mock数据
// 这个模块只需要引进来执行一次就可以,不需要import A from B,所以这个模块根本不用对外暴露
import '@/mock/mockServe';
因为只用执行,不调用里面的东西,也就不用获取这个模块,所以mockServer.js不用暴露,import的文件不论你导不导出都会全部编译一次,引入了就相当于执行了里面的代码。
*webpack默认对外暴露的有:图片、JSON数据格式
九、swiper插件的基本使用
1. 引包(相应的css、js)
2. 页面中的结构务必要有
3. new Swiper实例(给轮播图添加动态效果)
十、侦听器watch
监听组件实例身上的属性的属性值变化
Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
十一、nextTick
vm.$nextTick( [callback] )
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
回调的 this
自动绑定到调用它的实例上
该方法可以保证页面中的结构一定是有的,且经常和很多插件一起使用(很多插件需要DOM已经存在)
十二、本地存储
一些简单的数据skuNum通过query形式给路由组件传递过去,产品信息的数据skuInfo(较复杂),通过会话存储(不持久化,会话结束数据再消失)
浏览器存储功能:HTML5新增,本地存储、会话存储
本地存储localStorage:持久化的 ------ 5M
会话存储sessionStorage:并非持久 ------ 会话结束,数据就消失
本地存储、会话存储一般存储的是字符串,不能存对象,要先把对象转化成JSON字符串
十三、uuid 临时游客身份
发送请求时,获取不到购物车的数据,因为服务器不知道你是谁
解决方法:uuid 临时游客身份(也可以用nanoid)
1. 在utils的uuid_token.js文件中写一个生成uuid的函数
import { v4 as uuidv4 } from 'uuid';
// 这个函数要生成一个随机字符串,且每次执行不能发生变化,游客身份持久存储(localStorage)
export const getUUID = () => {
// 先从本地存储获取uuid(检查是否已经有了)
let uuid_token = localStorage.getItem('UUIDTOKEN');
// 如果没有就生成游客临时身份,本地存储存一次
if (!uuid_token) {
uuid_token = uuidv4();
localStorage.setItem('UUIDTOKEN', uuid_token);
}
return uuid_token;
}
2. 在vuex仓库的detail模块中使用
// 封装游客身份的模块uuid:生成一个随机字符串(生成一次不能再变了)
import { getUUID } from '@/utils/uuid_token'
const state = {
goodInfo: {},
// 游客的临时身份
uuid_token: getUUID(),
};
3. 在api请求文件的请求拦截器中,给请求头添加userTempId字段
// 1.请求拦截器:在发送请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use(config => {
// config是配置对象,里面有一个属性很重要,即headers请求头
if (store.state.detail.uuid_token) {
// 给请求头添加一个字段(userTempId),且该字段应该已经和后台商量好了才能加
config.headers.userTempId = store.state.detail.uuid_token;
};
// 进度条开始动
nprogress.start();
return config;
})
发送请求时就在请求头中带了这个参数,服务器就可以确定是谁把商品加入购物车的,购物车组件发送请求时就能获取到购物车的数据
十四、assets文件夹的作用
vue项目的assets文件夹用于放置全部组件共用的静态资源
十五、token
用户的唯一标识
登录业务:
1. 注册---通过数据库存储用户信息(名字、密码)
2. 登录---登录成功的时候,后台为了区分你这个用户是谁,服务器下发token(令牌,唯一标识符)
一般登录成功,服务器会下发token,前台持久化存储token(带着token找服务器要用户信息的数据进行展示)
注意:vuex仓库存储数据不是持久化的,一刷新就没了
十六、导航守卫
参数:
to: 要跳转到的路由的信息
from: 从哪个路由来
next: 放行函数
next();直接放行
next('/login');放行到指定路由
next(false);回到from的位置,即停留在当前位置(history模式下会导致路由清空router-view空白)
十七、注意事项
不能在生命周期函数上使用 async
十八、组件库
React:antd【PC端】,antd-mobile【移动端】
Vue:ElementUI【PC端】,vant【移动端】
十九、图片懒加载
vue-lazyload
vue-lazyload - npmhttps://www.npmjs.com/package/vue-lazyload
二十、表单验证
vee-validate
GitHub - logaretm/vee-validate: ✅ Form Validation for Vue.jshttps://github.com/logaretm/vee-validate
二十一、Linux 常用指令
cd 跳转目录
ls 查看
mkdir 创建目录
pwd 查看绝对路径