1、export 与 export default 区别
使用上不同
export default xxx
import xxx from './'
export xxx
import {xxx} from './'
2、什么是闭包
闭包其实是函数嵌套形成的域链
例如:有A、B两个函数,其中B函数在A函数中,并且B函数可以访问到A函数中的变量,那么B函数称为闭包
3、es6常用的功能
- 箭头函数'=>'
- promise 是异步编程的一种解决方案 包含resolve、reject、catch、all、race
- resolve :成功回调
- reject:失败调用
- catch:与then同级,抛出异常使用
- all:调用所有函数,并且以数组的形式,同时要求所有的方法都要成功,才可以
- race:与all相反,不论成功失败,只执行一次,并且是最快的那个
4、cookie是什么?持久cookie
- cookie是服务器返回的
- 持久cookie是带有的(有效期的)
5、数组去重
- es6 利用Set对象和数组的Array.from方法
arr=[...new Set(arr)];
es6方法数组去重,第二种方法
function dedupe(array) {
return Array.from(new Set(array)); //Array.from()能把set结构转换为数组
}
6、100递归求和
function add(num1,num2){
var num = num1+num2;
if(num2+1>100){
return num;
}else{
return add(num,num2+1)
}
}
var sum =add(1,2);
7、async/await能否单独使用?
async作为一个关键字放到函数前面,async函数执行会返回一个promise对象,并且把内部的值进行promise的封装。如果只是async, 和promise 差不多,但有了await就不一样了, await 关键字只能放到async 函数里面,await是等待的意思。它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果。 所以async可以单独使用,await不能,会报错
8、ES6
- 数组合并
const a = [1,2,3];
const b = [1,5,6];
const c = [...new Set([...a,...b])];//[1,2,3,5,6]
- 对象合并
const obj1 = {
a:1,
}
const obj2 = {
b:1,
}
const obj = {...obj1,...obj2};//{a:1,b:1}
- 取值
const obj = {
a:1,
b:2,
c:3,
d:4,
e:5,
}
const {a,b,c,d,e} = obj || {};
- 字符串拼接
const name = '小明';
const score = 59;
const result = `${name}${score > 60?'的考试成绩及格':'的考试成绩不及格'}`;
- 关于if条件
const condition = [1,2,3,4];
if( condition.includes(type) ){
//...
}
- 列表搜索
const a = [1,2,3,4,5];
const result = a.find(
item =>{
return item === 3
}
)
- 对象添加属性
let index = 1;
obj[`topic${index}`] = '话题内容';
9、axiox vue封装
- 引入
2. 创建axiox
const service = axios.create({ // 创建服务
baseURL: baseURL,//默认APi
timeout: 100000, // 请求延时
headers: {
'Cache-Control': 'no-cache' //请求头
},
paramsSerializer: function (params) {
return qs.stringify(params, {arrayFormat: 'repeat'}, {skipNulls: true})//请求参数序列化
},
validateStatus: function (status) {//设置状态
return true
}
})
- 统一封装请求
/**
* 这个处理登录方法
*/
function request(obj) {
let expires_in = localStorage.getItem('expires_in')
if (expires_in <= new Date().getTime() / 1000) {
return new Promise((resolve, reject) => {
let refresh_token = localStorage.getItem('refresh_token')
if (refresh_token) {
refreshToken(refresh_token).then((token) => {
let headers = {
Authorization: 'Bearer ' + token
}
if (localStorage.getItem('tenantId')) {
headers['tenantId'] = localStorage.getItem('tenantId')
}
obj.headers = headers
normal(obj).then(res => {
resolve(res)
})
})
}
})
} else {
let token = localStorage.getItem("Access-Token")
let headers = {
Authorization: 'Bearer ' + token
}
if (localStorage.getItem('tenantId')) {
headers['tenantId'] = localStorage.getItem('tenantId')
}
obj.headers = headers
return normal(obj)
}
}
//正常请求
function normal(obj) {
return new Promise((resolve, reject) => {
service(obj).then(res => {
if (res.status !== 200) {
message.error(res.data.message)
if (res.data.error === 'invalid_token') {
errorHandling()
}
} else {
if (res.status === 404) {
message.error('请求丢失')
}
resolve(res.data)
}
}).catch(res => {
errorHandling()
reject(res)
})
})
}
- get post del put
/**
* GET解析参数
*/
function get(url, params) {
return request({
url: url,
method: 'GET',
params
})
}
/**
* 请求方法
*/
function post(url, data) {
return request({
url: url,
method: 'POST',
data,
})
}
function put(url, data) {
return request({
url: url,
method: 'PUT',
data
})
}
function del(url, params) {
return request({
url: url,
method: 'DELETE',
params
})
}
- 总结
import axios from 'axios'
import qs from 'qs'
import cryptoJs from 'crypto-js'
import {message} from 'ant-design-vue'
const baseURL = ''
export default {
get,
post,
put,
del,
baseURL,
download,
login,
downloadURL,
downloadChangeName,
downloadAndName
}
/**
* 登录请求
*/
function login(params) {
params.password = encryptAES(params.password, 'C64EC4C5AEBDEC29FB2B3628C7FBA57E')
let config = {
baseURL: baseURL,
method: 'post',
url: '/small-service-auth/oauth/token',
timeout: 90000000,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic d2ViLXBjOndlYi1wYy1zdGFydA==',
},
params
};
return new Promise((resolve, reject) => {
axios(config).then(res => {
if (res.status !== 200) {
message.error("登录错误")
reject(res.data)
} else if (res.status === 200) {
if (res.data.status === 301) {
message.warning(res.data.message)
reject(res)
return;
}
let accessToken = res.data.access_token;
let expiresIn = res.data.expires_in;
localStorage.setItem('Access-Token', accessToken)
localStorage.setItem('expires_in', expiresIn + new Date().getTime() / 1000)
localStorage.setItem('refresh_token', res.data.refresh_token)
message.success('登录成功!')
resolve(res.data)
}
}).catch(res => {
message.error("登录失败,请检查网络!")
reject(res)
}).finally(res => {
reject(res)
})
})
}
const service = axios.create({ // 创建服务
baseURL: baseURL,
timeout: 100000, // 请求延时
headers: {
'Cache-Control': 'no-cache'
},
paramsSerializer: function (params) {
return qs.stringify(params, {arrayFormat: 'repeat'}, {skipNulls: true})
},
validateStatus: function (status) {
return true
}
})
/**
* GET解析参数
*/
function get(url, params) {
return request({
url: url,
method: 'GET',
params
})
}
/**
* 请求方法
*/
function post(url, data) {
return request({
url: url,
method: 'POST',
data,
})
}
function put(url, data) {
return request({
url: url,
method: 'PUT',
data
})
}
function del(url, params) {
return request({
url: url,
method: 'DELETE',
params
})
}
/**
* 这个处理登录方法
*/
function request(obj) {
let expires_in = localStorage.getItem('expires_in')
if (expires_in <= new Date().getTime() / 1000) {
return new Promise((resolve, reject) => {
let refresh_token = localStorage.getItem('refresh_token')
if (refresh_token) {
refreshToken(refresh_token).then((token) => {
let headers = {
Authorization: 'Bearer ' + token
}
if (localStorage.getItem('tenantId')) {
headers['tenantId'] = localStorage.getItem('tenantId')
}
obj.headers = headers
normal(obj).then(res => {
resolve(res)
})
})
}
})
} else {
let token = localStorage.getItem("Access-Token")
let headers = {
Authorization: 'Bearer ' + token
}
if (localStorage.getItem('tenantId')) {
headers['tenantId'] = localStorage.getItem('tenantId')
}
obj.headers = headers
return normal(obj)
}
}
//正常请求
function normal(obj) {
return new Promise((resolve, reject) => {
service(obj).then(res => {
if (res.status !== 200) {
message.error(res.data.message)
if (res.data.error === 'invalid_token') {
errorHandling()
}
} else {
if (res.status === 404) {
message.error('请求丢失')
}
resolve(res.data)
}
}).catch(res => {
errorHandling()
reject(res)
})
})
}
function download(url, params) {
// let token = localStorage.getItem("Access-Token");
let token = 'Bearer' + localStorage.getItem("Access-Token");
axios({
// baseURL: baseURL,
method: 'GET',
url: url,
params: params,
headers: {Authorization: token},
responseType: 'blob'
}).then(res => {
const blob = new Blob([res.data], {type: 'application/vnd.ms-excel;charset=utf-8'});
const fileName = `${new Date().valueOf()}.xls`;
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window.URL.revokeObjectURL(link.href);
}).catch(err => {
message.error("下载文件失败")
})
}
function downloadURL(url, fileName) {
axios({
method: 'GET',
url: url,
responseType: 'blob'
}).then(res => {
const blob = new Blob([res.data], {type: 'application/vnd.ms-excel;charset=utf-8'});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window.URL.revokeObjectURL(link.href);
}).catch(err => {
message.error("下载文件失败")
})
}
/**
* 更新token
*/
function refreshToken(refresh_token) {
return new Promise((resolve, reject) => {
axios({
url: baseURL + '/small-service-auth/oauth/token?grant_type=refresh_token&refresh_token=' + refresh_token,
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: 'Basic d2ViLXBjOndlYi1wYy1zdGFydA==',
'Content-Type': 'application/json;charset=UTF-8'
},
}).then(res => {
if (res.status === 200) {
localStorage.setItem('Access-Token', res.data.access_token)
localStorage.setItem('expires_in', res.data.expires_in + new Date().getTime() / 1000);
localStorage.setItem('refresh_token', res.data.refresh_token);
resolve(res.data.access_token)
} else {
errorHandling()
reject()
}
})
})
}
/**
* 错误处理
*/
function errorHandling() {
message.error('登录失效')
localStorage.clear()
// window.location.href = redirectURL + "/small-service-auth/oauth/authorize?client_id=web-pc&response_type=code"
}
//AES加密函数
function encryptAES(word, keyStr) {
let key = cryptoJs.enc.Utf8.parse(keyStr);
let srcs = cryptoJs.enc.Utf8.parse(word);
let encrypted = cryptoJs.AES.encrypt(srcs, key, {
mode: cryptoJs.mode.ECB,
padding: cryptoJs.pad.Pkcs7
});
return encrypted.toString();
}
// AES解密函數
function decryptAES(word, keyStr) {
let key = cryptoJs.enc.Utf8.parse(keyStr);
let decrypt = cryptoJs.AES.decrypt(word, key, {
mode: cryptoJs.mode.ECB,
padding: cryptoJs.pad.Pkcs7
});
return cryptoJs.enc.Utf8.stringify(decrypt).toString();
}
/**
* 获取 blob
* @param {String} url 目标文件地址
* @return {cb}
*/
function getBlob(url, cb) {
const xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob";
xhr.onload = function () {
if (xhr.status === 200) {
cb(xhr.response);
}
};
xhr.send();
}
/**
* 保存
* @param {Blob} blob
* @param {String} filename 想要保存的文件名称
*/
function saveAs(blob, filename) {
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, filename);
} else {
const link = document.createElement("a");
const body = document.querySelector("body");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
// fix Firefox
link.style.display = "none";
body.appendChild(link);
link.click();
body.removeChild(link);
window.URL.revokeObjectURL(link.href);
}
}
/**
* 下载
* @param {String} url 目标文件地址
* @param {String} filename 想要保存的文件名称
* 将此方法暴露出去
*/
function downloadChangeName(url, filename) {
getBlob(url, function (blob) {
saveAs(blob, filename);
});
}
/**
* 下载文件并带有文件名
* @param url
* @param params
*/
function downloadAndName(url, params) {
// let token = localStorage.getItem("Access-Token");
let token = 'Bearer' + localStorage.getItem("Access-Token");
axios({
// baseURL: baseURL,
method: 'GET',
url: url,
params: params,
headers: {Authorization: token},
responseType: 'blob'
}).then(res => {
const blob = new Blob([res.data], {type: 'application/vnd.ms-excel;charset=utf-8'});
//headers中获取文件名称
const disposition = res.headers["content-disposition"];
const fileName1 = disposition.substring(disposition.indexOf("=") + 1);
const fileName = decodeURI(fileName1);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window.URL.revokeObjectURL(link.href);
}).catch(err => {
message.error("下载文件失败")
})
}
10、vue 的优点?缺点
- 渐进式、虚拟dom、组件化、轻量级、响应式、单页面路由、视图与数据分开
- 单页面路由不利于seo ,首页加载漫、不支持IE8以下
11、怎么理解vue渐进式
渐进式:说白了就是,你想用什么就用什么,不想用就不用。
12、vue与react相同点与不同点
- 相同:①虚拟dom、②组件化、③支持服务端渲染、④单向数据流(父到子)
- 不同:①vue template而react jsx、②react单向绑定 vue双向绑定、③react的redux vue的vuex
13mvvm 是什么?与mvc 区别
- mvvm与mvc 是一种架构思想 m (model)模型,获取数据的,v(view)视图,展示的页面,c(controller)控制器,书写视图业务逻辑,vm(view-model)视图模型,类似双向绑定
- vm 视图模型是mvvm的核心,有两个方面①将模型转换成视图,即将后端传来的数据转换成视图展示出来,实现方式,数据绑定;②将视图转换成模型,即将我们看到的页面转化成后端数据,实现方式,dom事件监听。
- Mvvm定义MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。MVVM流程图如下:
4. MVC的定义:MVC是Model-View- Controller的简写。即模型-视图-控制器。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说MVVM实现的是业务逻辑组件的重用。
5. MVC的定义:MVC是Model-View- Controller的简写。即模型-视图-控制器。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说MVVM实现的是业务逻辑组件的重用。
14、### Vue和JQuery的区别在哪?为什么放弃JQuery用Vue?
- 1.jQuery是直接操作DOM,Vue不直接操作DOM,Vue的数据与视图是分开的,Vue只需要操作数据即可
- 2.在操作DOM频繁的场景里,jQuery的操作DOM行为是频繁的,而Vue利用虚拟DOM的技术,大大提高了更新DOM时的性能
- 3.Vue中不倡导直接操作DOM,开发者只需要把大部分精力放在数据层面上
- 4.Vue集成的一些库,大大提高开发效率,比如Vuex,Router等
15、为什么data是个函数并且返回一个对象呢?
data之所以是一个函数,是因为一个组件可能会多处调用,而每一次调用就会执行data函数并返回新的数据对象,这样,可以避免多处调用之间的数据污染。
15、组件之间的传值方式有哪些?
- 父组件传值给子组件,子组件使用
props进行接收 - 子组件传值给父组件,子组件使用
$emit+事件对父组件进行传值 - 组件中可以使用
$parent和$children获取到父组件实例和子组件实例,进而获取数据 - 使用
$attrs和$listeners,在对一些组件进行二次封装时可以方便传值,例如A->B->C - 使用
$refs获取组件实例,进而获取数据 - 使用
Vuex进行状态管理 - 使用
eventBus进行跨组件触发事件,进而传递数据 - 使用
provide和inject,官方建议我们不要用这个,我在看ElementUI源码时发现大量使用 - 使用浏览器本地缓存,例如
localStorage
16、路由有哪些模式呢?又有什么不同呢?
- hash模式:通过
#号后面的内容的更改,触发hashchange事件,实现路由切换 - history模式:通过
pushState和replaceState切换url,实现路由切换,需要后端配合
17、如何设置动态class,动态style?
- 动态class对象:
<div :class="{ 'is-active': true, 'red': isRed }"></div> - 动态class数组:
<div :class="['is-active', isRed ? 'red' : '' ]"></div> - 动态style对象:
<div :style="{ color: textColor, fontSize: '18px' }"></div> - 动态style数组:
<div :style="[{ color: textColor, fontSize: '18px' }, { fontWeight: '300' }]"></div>
18 js 数据类型
- 8种number null undefind string boolean object symbol bigint 后两个是es新增
- symbol 代表独一无二的值,用来定义对象唯一属性
- bigint 可以定义任意大小整数
19、判断变量是否是数组
- Array.isArray(arr); // true
- arr.proto === Array.prototype; // true
- arr instanceof Array; // true
- Object.prototype.toString.call(arr); // "[object Array]"