面试题 问题 与 简单解答

面试题总结

1.CSS 方面

1.如何实现盒子内的盒子水平垂直居中?

 

/* 第一种方式 */
父盒子 {
    display: flex; /* 开启 flex 布局 */
	justify-content: center; /* 盒子内的内容水平居中 */
	align-items: center; /* 盒子内的内容垂直居中 */
}

/* 第二种方式 */
父盒子 {
	position: relative; /* 父盒子开启 相对定位*/
}

子盒子 {
	position: absolute; /* 子盒子开启 绝对定位*/
	top: 50%;			/* 定位到父盒子的一半 */
	left: 50%;			/* 定位到父盒子的一半 */
	transform: translate(-50%, -50%); /* 负自身的一半 */
}

/* 第三种方式 */
父盒子 {
	position: relative; /* 父盒子开启 相对定位*/
}

子盒子 {
    position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	margin: auto;
}

2.移动端如何实现适配?

/* 1.利用媒体查询实现移动端适配 */

@media /* 开启媒体查询 */
screen /* 作用于屏幕 */
() /* 括号中写作用于多大的屏幕 */ 

/* 在小于或等于 992 像素的屏幕上,将背景色设置为蓝色 */
@media screen and (max-width: 992px) {
  body {
    background-color: blue;
  }
}

/* 2.rem */
/* rem 根据html跟标签的 font-size值 大小而变化 */
/* 计算单位 */
/* 640px = 6.40rem */
/* 缺点: 首次加载页面时, 会闪现一到两秒, 手机端体验不好 */

/* 3.媒体查询配合 rem */
/* 利用媒体查询不同屏幕宽度,设置不同的font-size */

@media screen and (width:750px){html{font-size:100px}}

@media screen and (width:749px){html{font-size:99.87px}}

@media screen and (width:748px){html{font-size:99.73px}}

@media screen and (width:321px){html{font-size:42.8px}}

@media screen and (width:320px){html{font-size:42.67px}}

3.如何实现双飞翼布局 ( 两边固定中间自适应 ) ?

// 1. 利用浮动实现
父盒子 {
    position: relative; /* 父盒子开启 相对定位*/
}

左侧盒子 {
     position: absolute;
     left: 0;
     top: 0;
}

中间盒子 {
    width: 100%;
}

右侧盒子 {
     position: absolute;
     right: 0;
     top: 0;
}
// 总结 父盒子开启相对定位, 左右侧盒子利用绝对定位 定位到两侧, 中间盒子宽度 100%

// 2. 用flex 布局实现
父盒子 {
        display: flex; // 开启 flex 布局
      }

中间盒子 {
    /* width: 100%; */
    flex: 1;
}
// 总结 父盒子开启 flex 布局 中间盒子 设置 宽度 100% 或者 使用 flex: 1; 都可

JavaScript

1.请说一下 深拷贝 和 浅拷贝 的区别?

浅拷贝

首先基础数据类型, 可以不分深浅拷贝, 因为进行赋值的时候, 是直接将数据池里的数据拿来直接给变量

  1. 浅拷贝

    1. 首先我们知道浅拷贝复杂数据类型的话, 都是直接赋值的引用地址, 可以理解为是把门牌号告诉了对方, 实际的数据都在存储池里存储

    2. 像赋值这种类型的操作就是浅拷贝, 如果同一条数据 赋值给多个 变量, 其中一个 更改了数据, 就会造成一改全改

  2. 深拷贝

    1. 由于我们知道 复杂数据类型的数据 全部都是使用的引用地址, 所以当多层复杂数据类型嵌套的时候, 即便用了自带的一些拷贝的方法, 也是只能拷贝第一层的数据, 深层的还是引用地址

    2. 所以深拷贝需要实现的是 需要将每一层嵌套的数据 全部拷贝到一个新的存储空间进行存储

2.如何实现深拷贝?

实现深拷贝有两种方式

 1. 利用 JSON 方法
 首先利用 JSON.stringify() 方法 将 要拷贝的数据转换为 JSON 字符串
 然后再用 JSON.parse() 方法 将 刚才的 JSON字符串 转化为 JSON 格式的数据
 上面两个操作实现深拷贝


 缺点
    用于是转换成 JSON 格式的数据 如果数据中存在 undefined 或者 一些方法时, 用此方法拷贝的数据会造成丢失

 2. 利用 递归 封装 递归方法 将数据中最小级别的基础数据类型, 一条一条解构出来一一将每个数据中的进行赋值 实现深拷贝

// 实现深拷贝有两种方式

// 1. 利用 JSON 方法
// 首先利用 JSON.stringify() 方法 将 要拷贝的数据转换为 JSON 字符串
// 然后再用 JSON.parse() 方法 将 刚才的 JSON字符串 转化为 JSON 格式的数据
// 上面两个操作实现深拷贝
// 缺点
//    用于是转换成 JSON 格式的数据 如果数据中存在 undefined 或者 一些方法时, 用此方法拷贝的数据会造成丢失

// 2. 利用 递归 封装 递归方法 将数据中最小级别的基础数据类型, 一条一条解构出来一一将每个数据中的进行赋值 实现深拷贝

// 封装的递归函数 - 此方法为最基础的 深拷贝方法
function deepClone1(obj) {
	//判断要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
	var objClone = Array.isArray(obj) ? [] : {};
	//进行深拷贝的不能为空,并且是对象或者是
	if(obj && typeof obj === "object") {
        // 因为 数组其实也是对象类型
        // 数组的索引  便是 对象类型的 key
        // 这就是为什么 数组 用 type of 判断类型的时候 显示的是 object 类型
		for(key in obj) {
			if(obj.hasOwnProperty(key)) {
				if(obj[key] && typeof obj[key] === "object") {
					objClone[key] = deepClone1(obj[key]);
				} else {
					objClone[key] = obj[key];
				}
			}
		}
	}
	return objClone;
}

3.es6新增了那些新特性?

  1. let const 声明变量

  2. 箭头函数

  3. 解构

  4. 扩展运算符

  5. 模板字符串

  6. set()

  7. promise

4.数组都有那些方法?

toString() 方法

该方法将数组中的字符串转换成(逗号分隔)的字符串

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
console.log(fruits.toString()); // Banana,Orange,Apple,Mango

join() 方法

可以将数组中的字符串按照指定字符进行拼接,拼接成字符串

方法类似于toString() 方法,但是它可以指定拼接的字符

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
console.log(fruits.join('*')); // Banana*Orange*Apple*Mango

删除数组中的元素

pop() 方法

该方法删除数组中最后一个元素,该方法返回值是当前被删除的元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.pop(); // 从 fruits 删除最后一个元素("Mango")
console.log(fruits); // ['Banana', 'Orange', 'Apple']

该方法返回值是当前被删除的元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
var x = fruits.pop(); // x 的值是 "Mango"
console.log(x); // Mango

shift() 方法

该方法会删除数组中首个元素,返回值是被删除的元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.shift();
console.log(fruits); // ['Orange', 'Apple', 'Mango']

该方法返回值是当前被删除的元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
var x = fruits.shift(); // x 的值是 "Banana"
console.log(x); // Banana

数组中添加元素的方法

push() 方法

该方法会将元素添加到数组的最后一个元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.push('Kiwi'); //  向 fruits 添加一个新元素
console.log(fruits); // ['Banana', 'Orange', 'Apple', 'Mango', 'Kiwi']

该方法返回值是添加后新数组的长度

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
var x = fruits.push('Kiwi'); //  x 的值是 5
console.log(x); // 5

unshift() 方法

该方法会在数组头部添加元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.unshift('Lemon'); // 向 fruits 添加新元素 "Lemon"
console.log(fruits); // ['Lemon', 'Banana', 'Orange', 'Apple', 'Mango']

该方法返回值是添加后新数组的长度

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
var x = fruits.unshift('Lemon'); //  x 的值是 5
console.log(x); // 5

数组增删改查方法

splice() 方法

该方法可以添加或者删除数组中的元素

第一个参数:定义数组中的位置

第二个参数:定义删除多少个元素,如果不删除就填写0

其余参数:就是要添加的元素

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.splice(2, 2, 'Lemon', 'Kiwi');
console.log(fruits); // ['Banana', 'Orange', 'Lemon', 'Kiwi']

裁剪数组

slice() 方法

该方法可以裁剪数组,该方法不会改变原数组,而是返回新的数组

该方法可以接受两个参数,包含开始索引元素,不包含结束索引元素

如果只传入一个参数,那么就从开始索引将后面全部元素全部切出

var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(3);
console.log(citrus); // ['Apple', 'Mango']
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3);
console.log(citrus); // ['Orange', 'Lemon']

翻转数组

reverse() 方法

该方法可以翻转数组元素,会更改原数组

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.reverse(); // 反转元素顺序
console.log(fruits); // ['Mango', 'Apple', 'Orange', 'Banana']

数组排序方法

sort() 方法

该方法可以将数组排序

数组中字符串按照首字母排序

var fruits = ['Banana', 'Orange', 'Apple', 'Mango'];
fruits.sort(); // 对 fruits 中的元素进行排序
console.log(fruits); // ['Apple', 'Banana', 'Mango', 'Orange']

数组可遍历方法

forEach()方法

该方法可以遍历数组的元素,该方法没有返回值,会更改原数组

方法内传入一个回调函数

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [45, 4, 9, 16, 25];
numbers.forEach((item, index, array) => {
    console.log(item);  // 第一个每一项遍历值
    console.log(index); // 第二个索引
    console.log(array); // 第三个数组本身
});

map()方法

该方法会遍历数组元素,不会更改原数组,return返回新数组

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [45, 4, 9, 16, 25];
numbers.forEach((item, index, array) => {
    console.log(item);  // 第一个每一项遍历值
    console.log(index); // 第二个索引
    console.log(array); // 第三个数组本身
    return value * 2
});

filter方法

该方法将通过测试的数组元素返回新数组

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [45, 4, 9, 16, 25];
numbers.forEach((item, index, array) => {
    console.log(item);  // 第一个每一项遍历值
    console.log(index); // 第二个索引
    console.log(array); // 第三个数组本身
    return value > 18
});
// 数组值的每一项会筛选出大于18的值

map和filter的区别

当return的值为布尔值时,map会将true和false返还为新数组,filter会将判断true,将true判断通过的数组元素返回为新数组元素

reduce()方法

该方法可以在每个数组元素上运行函数,以生成(减少它)的单个值,需要返回值

reduce()方法在数组中从左到右工作

reduce()方法不会减少原始数组

回调函数接收四个参数:

  • 总数(初始值/先前返回的值)

  • 项目值

  • 项目索引

  • 数组本身

// 该例子展示该方法用于计算总和
var numbers1 = [45, 4, 9, 16, 25];
numbers1.reduce((total, item, index, array) => {
    return total + value
})

reduce()方法可以接收一个初始值

// 该例子展示该方法用于计算总和
var numbers1 = [45, 4, 9, 16, 25];
numbers1.reduce((total, item, index, array) => {
    return total + value
}, 100)

every()方法

该方法用于检查数组值是否全部通过测试,全真则真,需要有return

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [45, 4, 9, 16, 25];
const result = numbers.every(item => {
    return item > 1;
});
console.log(result); // true

some()方法

该方法检查数组内是否有符合的数组值通过测试,一真全真,需要有return

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [45, 4, 9, 16, 25];
const result = numbers.some(item => {
    return item < 5;
});
console.log(result);

数组中查找方法

indexOf()方法

该方法可以搜索数组中的元素,并返回该元素位置,如果查找不到返回-1

var fruits = ['Apple', 'Orange', 'Apple', 'Mango'];
var a = fruits.indexOf('Apple');
console.log(a); // 0

该方法可接受两个参数

array.indexOf(item, start)
参数说明
item必需。要检索的项目。
start可选。从哪里开始搜索。负值将从结尾开始的给定位置开始,并搜索到结尾。

find()方法

该方法返回满足条件的第一个元素值,需要return

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [4, 9, 16, 25, 29];
var a = numbers.find(item => {
    return item > 18;
});
console.log(a); // 25

findIndex()方法

该方法返回满足条件的第一个元素的索引,需要return

回调函数内可接收三个参数

  • 第一个每一项遍历值

  • 第二个索引

  • 第三个数组本身

var numbers = [4, 9, 16, 25, 29];
var a = numbers.findIndex(item => {
    return item > 18;
});
console.log(a); // 3

5.说一下eventlop ( 事件执行机制 ) ?

首先

当我们编写了一段代码, 浏览器去执行, 因为JavaScript是单线程语言, 从上往下进行执行, 当遇到同步任务, 会直接执行, 当遇到异步任务, 会将异步任务 放到堆中, 当异步任务执行完毕后, 会放到任务队列中, 优先执行微任务, 其次执行宏任务

6.promise 属于什么任务?

promise 属于同步执行的宏任务, promise.then() 属于异步微任务

7.promise中如何处理并发请求(当有多个promise时, 如何 让他按照顺序执行, 获取结果)?

可以使用 promise.all() 方法

let a =  new Promise((resolve, reject) => {
  resolve('成功了')
})

let b =  new Promise((resolve, reject) => {
  resolve('success')
})

let c =  new Promise((resolve, reject) => {
  resolve('yes')
})

// 上面三个promise 需要 按照 成功了 success yes 顺序输出结果

Promise.all([a, b, c]).then(res => {
    console.log(res) // 打印结果 ['成功了', 'success', 'yes']
})

// 缺点
// 当其中一个 promise 失败, 所有的结果都会被排除到 .catch 中

8.用 async 和 await 如何接收错误(类似于 promise 中的.catch)?

利用 try catch 接收错误

// 使用方法
// 在 try 中 写入代码, 出现错误 会抛出到 catch 中
try {
    let list = await getList()
} catch (err) {
    console.log(err) // 打印接收的错误
}

9.实现下数组的冒泡排序?

// 1.利用 sort() 方法
let arr = [1, 3, 2, 5, 9];
arr.sort((a, b) => a - b);
console.log(arr); // [1, 2, 3, 5, 9] // 从小到大

let arr = [1, 3, 2, 5, 9];
arr.sort((a, b) => b - a);
console.log(arr); // [9, 5, 3, 2, 1] // 从大到小

// 2.利用 for循环 判断第二个是否小于前一个, 小于的话, 就先把 第一个赋值到一个空变量中, 第二个赋值给第一个, 再把空变量里存储的第一个赋值给第二个
let newNum;
for (let i = 0; i < arr.length; i++) {
	if (arr[i + 1] < arr[i]) {
		newNum = arr[i];
		arr[i] = arr[i + 1];
		arr[i + 1] = newNum;
	}
}
console.log(arr); //  [1, 2, 3, 5, 9] 从小到大

10.数组去重?

// 利用 set 方法去重
let arr = [1, 3, 3, 3, 2, 5, 9];
let newArr = Array.from(new Set(arr));
console.log(newArr); // [1, 3, 2, 5, 9]
// 由于new Set方法去重后的不是真数组, 所以需要使用 Array.from方法转化为真数组

// 利用双 for 去重
for (let i = 0; i < arr.length; i++) {
	for (let j = i + 1; j < arr.length - 1; j++) {
		if (arr[j] === arr[i]) {
			arr.splice(1, j);
		}
	}
}
console.log(arr); // [1, 3, 2, 5, 9]

// 原理
	// 双for遍历中的内循环可以每次将所有的内容, 逐个与数组的内容进行对比,if判断相同的利用splice方法,将相同的内容删除

vue

1.vue都有哪些常用指令?

v-for 循环

v-if

v-else-if

v-else

v-show

v-on 绑定事件

v-html

v-text

v-model

v-bind 绑定动态值

v-once 只渲染一次, 后续绑定值改变不会再次渲染

2.v-if 和 v-show的区别

v-if 是控制是否生成dom元素

v-show 是通过 css中的 display: none 进行显隐控制

优化

当需要频繁切换显隐状态的优先使用 v-show

3.v-model 为什么能够实现双向数据绑定?

简单说 v-model 就是一个语法糖

// 简单来说
v-model = v-bind:value + v-on:input

实现v-model

父组件使用 v-model

<子组件标签 v-model="父组件定义的变量值 />

子组件操作

<template>
	<p>子组件库存:{{ value }}</p>
	<button @click="add">增加1</button>
</template>
<script>
	export default {
		props:{
			value:{
				type: Number,
				default:0
			}
		},
		methods:{
			add() {
				this.$emit('input', this.value + 1)
			}
		}
	}
</script>
// 这样后每次点击按钮的时候,数据就会加1,并且把变更后的值传递给父组件
// 父组件 v-model 绑定的变量就会改变

4.简述一下vue的双向数据绑定原理?

简单来说 vue2 实现双向数据的核心是 Object.defineProperty() 方法

当我们调用的时候 会触发里面的get方法, 当赋值的时候会触发里面的set方法

var obj = {};
Object.defineProperty(obj,'hello',{
  get: function(){
    console.log('调用了get方法')
  },
  set: function(newValue){
    console.log('调用了set方法,方法的值是' + newValue);
  }
});
obj.hello; // => '调用了get方法'
obj.hello = 'hi'; // => '调用了set方法,方法的值是hi'

简单实现双向绑定

<input type="text" />
<p></p>
<script>
	let input = document.querySelector('input');
	let p = document.querySelector('p');
	let obj = {};
	let value = '';
	Object.defineProperty(obj, 'inputvalue', {
		get() {
				return value;
			},
		set(newValue) {
			input.value = newValue;
			p.innerHTML = newValue;
		},
	});
	// 订阅者 DOM元素
	input.value = obj.inputvalue;
	p.innerHTML = obj.inputvalue;
	// 监听输入的事件
	input.addEventListener('keyup', function (e) {
		// 修改inputvalue 达到修改input.value 以及input.innerHTML
		// 发布者
		obj.inputvalue = e.target.value; // 触发了set
	});
</script>

5.vue 组件间如何传参

1.父子组件传参

父传子

父组件在子组件标签上通过 属性传参

子组件通过 props 进行接收

子传父

子组件通过 $emit 派发事件, 第二个参数 传递参数

父组件 监听事件, 绑定方法通过回调接收参数

2.跨组件传参

非父子组件传参, 兄弟组件传参

1.eventBus

eventBus 相当于创建了一个空的 vue实例, 利用自带的方法进行传参, 利用 $emit 派发事件 $on监听(接收)

2.利用 vuex

6.什么是vuex?

vuex 是一个 专为vue 开发一个状态管理器

vuex的五大核心

  1. state ---> 存储数据

  2. getters ---> 类似于 vue 中的 computed

  3. mutations ---> 用于更改数据的方法, 同步!

  4. actions ---> 做一些异步操作

  5. modules ---> 模块化vuex

7.vue 的生命周期?

vue 一共有四个生命周期, 八个生命周期钩子函数

  1. beforeCreate(创建前)

  2. created(创建后)

  3. beforeMount(载入前)

  4. mounted(载入后)

  5. beforeUpdate(更新前)

  6. updated(更新后)

  7. beforeDestroy(销毁前)

  8. destroyed(销毁后)

8.说一下 computed 和 watch 的区别?

computed

作用是用来计算结果, 必须有返回值, 方法名可以当做变量名使用

computed 优点也是带缓存, 当计算的基础数据不变, 不会每次重新计算

watch

watch 的作用是用来监听数据的改变来做一些操作

9.常用的修饰符?

v-on 指令常用修饰符 - 事件修饰符

  1. .stop 禁止事件冒泡

  2. .prevent - 调用 event.preventDefault(),阻止事件默认行为。

  3. .self - 与.stop类似, 绑定的事件只会作用于当前绑定的元素。

  4. .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。

  5. .native - 监听组件根元素的原生事件。

  6. .once - 只触发一次回调。

.native 作用

当我们给组件添加原生的事件的时候, 发现不生效, 是什么原因呢?

组件上的事件, 会被认为是自定义事件, 如果子组件内没有做过处理, 就不会生效

那如果我们想直接在子组件的跟标签上绑定事件, 如何操作?

那就需要到 .native 修饰符了, 在事件后添加.native 修饰符, 就会将该事件, 绑定到组件内的跟标签上

v-model 指令常用修饰符

  1. .lazy - 取代 input 监听 change 事件

  2. .number - 输入字符串转为数字

  3. .trim - 输入首尾空格过滤

10.为什么组件中的data是函数?

因为js中的对象是引用关系

如果 data 直接是个对象, 那么作用域就没有被隔离, 如果有相同的变量数据, 会造成一改全改

但如果data 是函数 然后将对象return 出去, 就会重新开辟一个存储空间进行存储数据, 就会有独立的作用域

11.vue中 key 值的作用?

key 用来给 每个节点 做唯一标识

搭配 diff 算法能够 高效的更新虚拟 DOM

12.说一下vue的虚拟dom和diff算法

虚拟dom,顾名思义就是不是真实dom,虚拟dom是根据真实dom映射出来的一个js对象

diff算法根据key去遍历虚拟dom树,一层一层的去查找,找到需要更改的dom进行,更改,不会触发dom树的重构,从而实现性能优化

13.v-for 能和 v-if 同时使用吗?

不建议同时使用

因为 v-for 的优先级 比 v-if 高, 所以每次渲染是都会先循环出来 在进行条件判断, 搭配使用会特别消耗性能, 如果有 语法检查, 则会报语法的错误

14.vue 路由都有那些守卫?

vue 中 路由守卫一共有三种,

分别为:

  1. 全局路由守卫(全局前置守卫、全局后置守卫)

  2. 组件内路由守卫

  3. 路由独享守卫(是在路由配置页面单独给路由配置的一个守卫)

全局路由守卫

全局前置守卫

当路由跳转前会触发到该守卫

可以再路由跳转前判断, 是否存在token, 如果不存在, 跳转回登录页面

全局后置守卫

当路由跳转后会触发到该守卫

全局守卫

// 全局前置守卫
router.beforeEach((to, from, next) => {
    // to 进入到哪个路由去
    // from 来自哪个路由
    // next 函数, 决定是否放行
    if(to.path == '/login' || to.path == '/register'){
    	next();
  	}else{
    	alert('您还没有登录,请先登录');
    	next('/login');
  }
})

// 全局后置守卫
router.afterEach((to,from)=>{
  alert("after each");
})

组件内的守卫

// 组件内的守卫
 // 进入组件触发该守卫
 beforeRouteEnter:(to,from,next)=>{
     // 由于进入组件时, data数据还未渲染
     // 所以无法直接调用 data中的数据
     // 需要使用 next 中的 回调参数获取data数据
   next(vm=>{
        alert("hello" + vm.name);
   })
 }
 
 // 离开组件触发该守卫
beforeRouteLeave:(to,from,next)=>{
  if(confirm("确定离开此页面吗?") == true){
     next();
  }else{
     next(false);
  }
}

路由独享守卫

// 路由独享守卫
beforeEnter:(to,from,next)=>{}
// 用法与全局守卫一样, 将其写进其中一个路由对象中, 只在这个路由下起作用

15.route 和 router 的区别是什么?

router是 路由实例, 其中包含了路由跳转的方法 和 钩子函数等

route 是路由信息对象, 每一个路由都会有一个 route 对象, 其中包含当前路由的路由信息

16.vue项目都有哪些优化方案?

  1. 使用 CDN 资源

  2. v-for 添加 key 方便diff 算法查找

  3. 使用 v-for的时候 避免同时使用 v-if, 因为由于 v-for 优先级更高 v-if将分别重复运行与每个循环中, 将会影响速度

  4. 当涉及到计算结果的时候 使用 computed, 因为 computed 带缓存, 只有当依赖值发生变化时, 才会重新计算

  5. 路由懒加载

  6. 第三方库按需引入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值