2020前端面试

一、什么是路由,路由的实现原理

路由:根据URL地址,跳转到相应页面,vue中通过使用路由进行组件切换
路由填充位(也叫做路由占位符):<router-view></router-view>将来通过路由规则匹配到的组件,将会被渲染到 router-view 所在的位置
在这里插入图片描述
路由导航守卫都有那些钩子函数?说明在什么场景下会触发这些钩子函数。
vue-router 的导航钩子,主要用来作用是拦截导航,让他完成跳转或取消。

全局守卫
router.beforeEach:全局前置守卫,进入路由之前
router.afterEach:全局后置钩子,进入路由之后
路由组件内的守卫
beforeRouteEnter():进入路由前
beforeRouteUpdate():路由复用同一个组件时
beforeRouteLeave():离开当前路由时
独享守卫
beforeEnter:进入路由之前
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

$route$router 的区别
routerVueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。。。

route相当于当前正在跳转的路由对象。可以从里面获取name,path,params,query等。。

vue-router的两种模式
1.hash模式URLhash 是以#开头,是基于location.hash来实现的。Location.hash的值就是URL中#后面的内容。当hash改变时,页面不会因此刷新,浏览器也不会请求服务器。
同时,hash 改变时,并触出发相应的hashchange事件,所以,hash很适合被用来做前端路由。当hash路由发生跳转,便会触发hashchange回调,回调里面就可以实现页面的更新操作,从而达到跳转页面的效果。

2.HTML的history模式:history丢掉了#,操作中不怕前进和后退,就怕刷新,如果没有服务端的支持,刷新之后就会去请求服务器,由于找不到相应的支持响应或者资源,就会报出404页面。
history api可以分为两大部分:切换和修改

1、切换历史状态包括back、forward、go
这三个方法,对应浏览器的前进,后退,跳转操作;(跳转操作:在前进后退上长按鼠标,会出来所有当前窗口的历史记录,从而可以跳转)

history.go(-2);//后退两次
history.go(2);//前进两次
history.back(); //后退
hsitory.forward(); //前进

2、修改历史状态包括了 pushState, replaceState两个方法
这两个方法接收三个参数:stateObj, title, url

window.history.pushState(state, title, url) 
// state:需要保存的数据,这个数据在触发popstate事件时,可以在event.state里获取
// title:标题,基本没用,一般传 null
// url:设定新的历史记录的 url。新的 url 与当前 url 的 origin 必须是一樣的,否则会抛出错误。url可以是绝对路径,也可以是相对路径。
//如 当前url是 https://www.baidu.com/a/,执行history.pushState(null, null, './qq/'),则变成 https://www.baidu.com/a/qq/,
//执行history.pushState(null, null, '/qq/'),则变成 https://www.baidu.com/qq/
 
window.history.replaceState(state, title, url)
// 与 pushState 基本相同,但她是修改当前历史记录,而 pushState 是创建新的历史记录
 
window.addEventListener("popstate", function() {
    // 监听浏览器前进后退事件,pushState 与 replaceState 方法不会触发              
});

使用history模式出现404解决方法:
使用nginx服务器
配置nginx
这里的配置意思是将所有的文件都指向Index.html文件,然后再给一个404的错误提示页面

server {
        listen       8089; // 端口
        server_name  localhost; // 访问地址,默认是本机
       location / {
            try_files $uri $uri/ @router; // 需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
            index  index.html index.htm;
        }
        // 对应上面的@router,主要原因是路由的路径资源并不是一个真实的路径,所以无法找到具体的文件
        #因此需要rewrite到index.html中,然后交给路由在处理请求资源
        location @router {
            rewrite ^.*$ /index.html last;
        }

两种模式的区别
1. history设置的新url可以是与当前url同源的任意值;hash只可修改 # 后面的部分,实质上是同文档的url;
2. history设置的新url可以与当前url相同,依然会把记录添加到栈中;hash必须不一样才会添加;
3. history通过stateObject参数可以添加任意类型的数据到记录中;hash只可添加短字符串;
4.history可额外设置title属性;

路由懒加载的三种方法
1.vue异步组件

/* vue异步组件技术 */
{
  path: '/home',
  name: 'home',
  component: resolve => require(['@/components/home'],resolve)
},{
  path: '/index',
  name: 'Index',
  component: resolve => require(['@/components/index'],resolve)
}

2.es提案的import()

const List = () => import('@/components/list.vue')
const router = new VueRouter({
  routes: [
    { path: '/list', component: List }
  ]
})

3.webpackrequire,ensure()

/* 组件懒加载方案三: webpack提供的require.ensure() */
{
  path: '/home',
  name: 'home',
  component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
  path: '/index',
  name: 'Index',
  component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}

一、CSS性能优化

1.尽量使用缩写:p { margin: 1px 2px 3px 4px; }
2.查找并删除未使用的 CSS
3. 文件压缩
4.避免需要性能要求的属性(border-radius box-shadow transform filter :nth-child position: fixed;)
5. 优化重排与重绘
避免不必要的重绘:当元素的外观(如color,background,visibility等属性)发生改变时,会触发重绘。在网站的使用过程中,重绘是无法避免的。不过,浏览器对此做了优化,它会将多次的重排、重绘操作合并为一次执行。
不过我们仍需要避免不必要的重绘,如页面滚动时触发的hover事件,可以在滚动的时候禁用hover事件,这样页面在滚动时会更加流畅。

6.减少使用 @import, 而建议使用link, 因为后者在页面加载时一起加载,前者是等待页面加载完成之后再进行加载;
1、首先,使用@import引入CSS会影响浏览器的并行下载。使用@import引用的CSS文件只有在引用它的那个css文件被下载、解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析、构建render tree等一系列操作。
这就导致浏览器无法并行下载所需的样式文件。
2、其次,多个@import会导致下载顺序紊乱。在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件先于@import下载,并且打乱甚至破坏@import自身的并行下载。

二、javascript定时器,取消定时器,及js定时器优化方法

一般不用setInterval,而用setTimeout的延时递归来代替interval。
setInterval会产生回调堆积,特别是时间很短的时候。

三、v-model的原理,还有没有其他方法实现?

v-model只是一个语法糖,等于:value+@input,真正的实现靠的还是: v-bind:绑定响应式数据,触发 input 事件并传递数据 (核心和重点)
<input v-model="something">
其实和下面一样的
<input :value="something" @input="something = $event.target.value">
因此,对于一个带有 v-model 的输入框组件,它应该:接收一个 value prop,触发 input 事件,并传入新值
自定义myInput组件

<template>
  <div style="padding-top: 100px;">
    <button @click="minu"  class="btn">-</button>
        <input type="text" :value="currentValue" @input="handleInput" />
    <button @click="plus" class="btn">+</button>
  </div>
</template>
<script>
export default {
  props:['value'],
    data () {
    return {}
  },
  computed:{
  	currentValue:function(){
  		return this.value
  	}
  },
  methods:{
  	handleInput:function(event){
      	this.$emit('input', event.target.value); //触发 input 事件,并传入新值
  	},
  	minu:function(){
  		this.$emit('input', this.currentValue - 1 );
  	},
  	plus:function(){
  		this.$emit('input',  this.currentValue + 1 );
  	},
  }
}
</script>
<style type="text/css">
	.btn{
		width: 60px;
	}
</style>

总结:
自定义的组件内部一般包含原生的表单组件(当然非表单的组件也可以),然后给原生控件绑定事件,捕捉到原生组件的值,利用 $emit方法,触发input方法,组件监听到 input事件然后把值传入
v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
texttextarea 元素使用 value 属性和 input 事件;
checkboxradio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

在这里插入图片描述

六、Vue中的created和mounted的区别

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

八、splice,slice,substr,substring区别总结

1.splice():删除、添加原数组;数组使用,会改变原数组;参数一:要操作的位置下标(即在该下标开始进行添加或删除);参数二:要删除的数组个数;参数三:在下标为参数一的位置添加的内容;返回值为删除各项所组成的新数组,无删除时则返回空数组。

var str = ["as","dfg","hj"];
var str_splice = str.splice(1,0,"hh"); 
console.log(str);    // ["as","hh","dfg","hj"]
console.log(str_splice);    //[]

2.slice():数组、字符串位置截取;数组、字符串均可使用;参数一:开始截取的下标;参数二:截取的截止位置但不包含该下标;返回截取的新数组。

var str = ["as","hh","dfg","hj"];
var str_slice = str.slice(1,3);    //["hh","dfg"]

3.substr()截取指定长度字符串;字符串使用,用于截取指定长度字符串;参数一:开始截取的下标位置;参数二:要截取的字符串长度;返回截取的新字符串。

var str = "as-dfg-hj";
var str_substr = str.substr(1,4);    //s-df

4.substring()字符串位置截取;字符串使用;参数一:开始截取位置;参数二:结束截取下标,但不包含该下标字符;返回截取的新字符串;(第二个参数应该大于第一个参数,如果出现第一个参数大于第二个参数的情况,substring方法会自动更换两个参数的位置)

var str = "as-dfg-hj";
var str_substring = str.substring(1,4);    //s-d
十、vuex
  • State:所有共享的数据都要统一放到 Store 的 State 中进行存储
    组件访问 State 中数据的:this.$store.state.全局数据名称
    组件访问 State 中数据的第二种方式:从 vuex 中按需导入 mapState 函数

  • Mutation 用于变更 Store中 的数据。
    ① 只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据。
    ② 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
    this.$store.commit() 是触发 mutations 的方法

  • Action 用于处理异步任务。
    如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但是在 Action中还是要通过触发 Mutation 的方式间接变更数据。
    this.$store.dispatch() 是触发 actions的方法
    在这里插入图片描述

  • Getter 用于对 Store 中的数据进行加工处理形成新的数据。
    Getter 可以对 Store中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性。
    Store 中数据发生变化,Getter 的数据也会跟着变化。
    使用方法:this.$store.getters.名称

十一、为什么 vue 组件中 data 必须是一个函数?

对象为引用类型,当复用组件时,由于数据对象都指向同一个 data 对象,当在一个组件中修改 data 时,其他重用的组件中的 data 会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object 的实例),引用地址不同,则不会出现这个问题。

十五、Vue中子组件修改父组件传递过来的props,并不影响父组件的原始数据

这仅限于props为非数组及对象等引用类型数据,譬如字符串,数字等
如果props是对象或数组的话,在子组件内修改props的话,父组件是不会报错的。
那么要怎么解决修改props传的值而不污染父组件的值:
1,可以使用ES6提供的Object.assign({}, prop)的返回值就是一个全新的对象,操作这个新对象不会影响旧对象。如果不用ES6就自己递归实现拷贝器
2,可以给对象重新赋值:(给对象里的每一项重新赋值)

十六、vuex传递数据页面刷新

页面刷新store.state中的数据消失是不可避免的,那么使用localStorage来避免这个问题。发现问题的时候我就考虑到存数据在localStorage里,但是一个一个数据添加实在是太蠢了。那么就需要一个全局的方法来,将store的数据存储在localStorage里。具体的方法也是百度的很好用,也很方便。
在App.vue中,created初始化生命周期中写入以下方法

//在页面刷新时将vuex里的信息保存到localStorage里
window.addEventListener("beforeunload",()=>{
  localStorage.setItem("messageStore",JSON.stringify(this.$store.state))
})
 
//在页面加载时读取localStorage里的状态信息
localStorage.getItem("messageStore") && this.$store.replaceState(Object.assign(this.$store.state,JSON.parse(localStorage.getItem("messageStore"))));

replaceState这个方法呢,查了api,就是替换 store 的根状态,然后通过对象赋值assignlocalStorage进行赋值

beforeunload这个方法是在页面刷新时触发的,将store中的信息存入localStorage

这样就通过localStorage来避免vuex刷新数据消失的问题了。

十八、原生JS获取HTML DOM元素的8种方法

在这里插入图片描述

十九、获取url参数转为对象

把字符串转为对象

    // 把字符串转化为对象
    var str = 'id=1&name=zhangsan&age=18&className=2003'
    // {id:1,name:zhangsan,age:18,className:2003}
    // 先把字符串转化为 数组
    var arr = str.split('&');
    // arr = ['id=1','name=zhangsan','age=18','className=2003']

    var obj = {};
    for (var i = 0; i < arr.length; i++) {
      // arr[i].split('=')  ['id',1]
      var newArr = arr[i].split('=');
      // ['id','1']  ['name':'zhangsan']
      obj[newArr[0]] = newArr[1];
    }
    console.log(obj);

把对象转为字符串

   // 把对象转化为字符串
    var obj1 = {
      id: 1,
      name: 'zhangsan',
      age: 18,
      className: 2003
    }
    // 'id=1&name=zhangsan&age=18&className=2003'
    var str1 = '';
    // 遍历对象
    for (var key in obj1) {
      str1 += key + '=' + obj1[key] + '&';
    }
    // 去掉最后一个 & 
    console.log(str1.substr(0, str1.length - 1));

封装字符串转为对象函数

    var str = 'id=1&name=fqniu&age=25&workName=frontEnd'
    // strUrlObj 为字符串转为对象的函数名
    function strUrlObj(string) {
      // 去掉字符串中的 & 的数组
      let strArray = string.split('&')
      //console.log(strArray)  //["id=1", "name=fqniu", "age=25", "workName=frontEnd"]
      // 定义一个空对象
      let obj = {}
      for (let i = 0; i < strArray.length; i++) {
        // 定义一个新的数组来接收 去掉字符串中的 = 的数组
        let newArray = strArray[i].split('=')
        // console.log(newArray)
        // 然后遍历添加每个数组中对应的数据 添加到对象中
        obj[newArray[0]] = newArray[1]
      }
      return obj
    }
    console.log(strUrlObj(str))
    //{id: "1", name: "fqniu", age: "18",workName: "frontEnd"}
 
二十、for…in与for…of的区别

for in 返回数组的下标(key);
for of 返回数组的元素;
for of不可以遍历普通对象,想要遍历对象的属性,可以用for in循环, 或Object.keys()方法。
在这里插入图片描述

二十一、Vue 常见性能优化方式

合理使用 v-showv-if
合理使用 computed
v-for 时要加 key,以及避免和 v-if 同时使用
自定义事件、DOM 事件及时销毁
合理使用异步组件
合理使用 keep-alive
data 层级不要太深(因为深度监听一次性监听到底)
使用 vue-loader 在开发环境做模板编译(预编译)
webpack 层面的优化

二十二、 target、currentTarget 的区别?

currentTarget 当前所绑定事件的元素
target 当前被点击的元素

二十三、 用 js 递归的方式写 1 到 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); 
   console.log(sum)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值