前端笔记

145 阅读8分钟

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常用的功能

  1. 箭头函数'=>'
  2. promise 是异步编程的一种解决方案 包含resolve、reject、catch、all、race
  3. resolve :成功回调
  4. reject:失败调用
  5. catch:与then同级,抛出异常使用
  6. all:调用所有函数,并且以数组的形式,同时要求所有的方法都要成功,才可以
  7. race:与all相反,不论成功失败,只执行一次,并且是最快的那个

4、cookie是什么?持久cookie

  1. cookie是服务器返回的
  2. 持久cookie是带有的(有效期的)

5、数组去重

  1. 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

  1. 数组合并
const a = [1,2,3];
const b = [1,5,6];
const c = [...new Set([...a,...b])];//[1,2,3,5,6]
  1. 对象合并
const obj1 = {
a:1,
}
const obj2 = {
b:1,
}
const obj = {...obj1,...obj2};//{a:1,b:1}
  1. 取值
const obj = {
a:1,
b:2,
c:3,
d:4,
e:5,
}
const {a,b,c,d,e} = obj || {};
  1. 字符串拼接
const name = '小明';
const score = 59;
const result = `${name}${score > 60?'的考试成绩及格':'的考试成绩不及格'}`;
  1. 关于if条件
const condition = [1,2,3,4];

if( condition.includes(type) ){
//...
}
  1. 列表搜索
const a = [1,2,3,4,5];
const result = a.find(
item =>{
return item === 3
}
)
  1. 对象添加属性
let index = 1;
obj[`topic${index}`] = '话题内容';

9、axiox vue封装

  1. 引入

image.png 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
  }
})
  1. 统一封装请求
/**
 * 这个处理登录方法
 */
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)
    })
  })
}
  1. 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
  })
}
  1. 总结
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 的优点?缺点

  1. 渐进式、虚拟dom、组件化、轻量级、响应式、单页面路由、视图与数据分开
  2. 单页面路由不利于seo ,首页加载漫、不支持IE8以下

11、怎么理解vue渐进式

渐进式:说白了就是,你想用什么就用什么,不想用就不用。

12、vue与react相同点与不同点

  • 相同:①虚拟dom、②组件化、③支持服务端渲染、④单向数据流(父到子)
  • 不同:①vue template而react jsx、②react单向绑定 vue双向绑定、③react的redux vue的vuex

13mvvm 是什么?与mvc 区别

  1. mvvm与mvc 是一种架构思想 m (model)模型,获取数据的,v(view)视图,展示的页面,c(controller)控制器,书写视图业务逻辑,vm(view-model)视图模型,类似双向绑定
  2. vm 视图模型是mvvm的核心,有两个方面①将模型转换成视图,即将后端传来的数据转换成视图展示出来,实现方式,数据绑定;②将视图转换成模型,即将我们看到的页面转化成后端数据,实现方式,dom事件监听。
  3. Mvvm定义MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。MVVM流程图如下:

u=32561255,2826043542&fm=173&app=25&f=JPEG.jpg
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实现的是业务逻辑组件的重用。

u=1581589677,2197583542&fm=173&app=25&f=JPEG.jpg

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进行跨组件触发事件,进而传递数据
  • 使用provideinject,官方建议我们不要用这个,我在看ElementUI源码时发现大量使用
  • 使用浏览器本地缓存,例如localStorage

16、路由有哪些模式呢?又有什么不同呢?

  • hash模式:通过#号后面的内容的更改,触发hashchange事件,实现路由切换
  • history模式:通过pushStatereplaceState切换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 数据类型

  1. 8种number null undefind string boolean object symbol bigint 后两个是es新增
  2. symbol 代表独一无二的值,用来定义对象唯一属性
  3. bigint 可以定义任意大小整数

19、判断变量是否是数组

  • Array.isArray(arr); // true
  • arr.proto === Array.prototype; // true
  • arr instanceof Array; // true
  • Object.prototype.toString.call(arr); // "[object Array]"