精华内容
下载资源
问答
  • 前端vue面试题
    2020-10-22 00:13:24

    @VUE面试题

    VUE面试题

    第一章 VUE基础

    1. vue的优点
    2. 1、轻量级框架 只关注视图层,是一个构建数据的视图集合,大小只有几十kb Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统
      2、简单易学 国人开发,中文文档,不存在语言障碍,易于理解和学习
      3、双向数据绑定 也就是所谓的响应式数据绑定。这里的响应式不是@media 媒体查询中的响应式布局,而是指vue.js会自动对页面中某些数据的变化做出同步的响应。
      也就是说,vue.js会自动响应数据的变化情况,并且根据用户在代码中预先写好的绑定关系,对所有绑定在一起的数据和视图内容都进行修改。而这种绑定关系,就是以input 标签的v-model属性来声明的,因此你在别的地方可能也会看到有人粗略的称vue.js为声明式渲染的模版引擎。
      这也就是vue.js最大的优点,通过MVVM思想实现数据的双向绑定,让开发者不用再操作dom对象,有更多的时间去思考业务逻辑。
      4、组件化
      在前端应用,我们是否也可以像编程一样把模块封装呢?这就引入了组件化开发的思想。
      Vue.js通过组件,把一个单页应用中的各种模块拆分到一个一个单独的组件(component)中,我们只要先在父级应用中写好各种组件标签(占坑),并且在组件标签中写好要传入组件的参数(就像给函数传入参数一样,这个参数叫做组件的属性),然后再分别写好各种组件的实现&

    更多相关内容
  • 2021年前端vue面试题大汇总(附答案).pdf
  • 由于疫情原因,原本每年的“金三银四”仿佛消失,随之而来的是找工作的压力,这里给要面试的小伙伴们总结了到目前为止我遇到的前端面试题,仅供参考哦,第一次写博客,如有错误之处,还请指出。 一. vue方面 1.vue-...
  • 前端面试题: 精选Vue面试题及答案.pdf
  • 2021最新通用BAT大厂前端vue面试题.pdf
  • 2022前端面试系列——Vue面试题.pdf
  • 35道常见的前端vue面试题

    万次阅读 多人点赞 2021-03-06 00:04:32
    来源 | https://segmentfault.com/a/1190000021936876今天这篇文章给大家分享一些常见的前端vue面试题。有一定的参考价值,有需要的朋友可以参考一下...

    来源 | https://segmentfault.com/a/1190000021936876

    今天这篇文章给大家分享一些常见的前端vue面试题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

    对于前端来说,尽管css、html、js是主要的基础知识,但是随着技术的不断发展,出现了很多优秀的mv*框架以及小程序框架。因此,对于前端开发者而言,需要对一些前端框架进行熟练掌握。这篇文章我们一起来聊一聊VUE及全家桶的常见面试问题。

    1、请讲述下VUE的MVVM的理解?

    MVVM 是 Model-View-ViewModel的缩写,即将数据模型与数据表现层通过数据驱动进行分离,从而只需要关系数据模型的开发,而不需要考虑页面的表现,具体说来如下:

    Model代表数据模型:主要用于定义数据和操作的业务逻辑。

    View代表页面展示组件(即dom展现形式):负责将数据模型转化成UI 展现出来。

    ViewModel为model和view之间的桥梁:监听模型数据的改变和控制视图行为、处理用户交互。通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉

    在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

    2、VUE的生命周期及理解?

    答:总共分为8个阶段,具体为:创建前/后,载入前/后,更新前/后,销毁前/后。

    创建前/后: 在beforeCreated阶段:ue实例的挂载元素$el和数据对象data都为undefined,还未初始化;在created阶段,vue实例的数据对象data有了,$el还没有。

    载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换;在mounted阶段,vue实例挂载完成,data.message成功渲染。

    更新前/后:当data变化时,会触发beforeUpdate和updated方法。

    销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。

    具体讲解及应用

    beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法

    create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作

    beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的,不能直接操作页面的dom和获取dom对象

    mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行

    beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的,页面还没有和最新的数据保持同步

    updated:页面显示的数据和data中的数据已经保持同步了,都是最新的

    beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的data和 methods、指令、过滤器 ……都是处于可用状态。还没有真正被销毁

    destroyed: 这个时候上所有的data和methods、指令、过滤器 ……都是处于不可用状态。组件已经被销毁了。

    3、v-if和v-show的区别?

    共同点:都能控制元素的显示和隐藏;

    不同点:实现本质方法不同,v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。

    如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。

    4、v-if和v-for同时使用在同一个标签上的表现?

    当v-if与v-for一起使用时,v-for具有比v-if更高的优先级,这意味着v-if将分别重复运行于每个v-for循环中。
    所以,不推荐v-if和v-for同时使用。如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去

    5、v-for中的key的理解?

    需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。主要是为了高效的更新虚拟DOM。

    6、vue中transition的理解?

    1)定义transition时需要设置对应的name,具体语法为:<transition name=“fade”>需要动画的内容或者组件或者页面</transition>

    2)过渡动画主要包含6个class,分别为:

    • v-enter:定义元素进入过渡的初始状态,在元素插入前生效,插入后一帧删除,

    • v-enter-active:在元素插入前生效,在动画完成后删除,

    • v-enter-to:在元素插入后一帧生效,在动画完成后删除,

    • v-leave:离开过渡的初始状态,在元素离开时生效,下一帧删除

    • v-leave-active:在离开过渡时生效,在动画完成后删除

    • v-leave-to:离开过渡结束状态,在离开过渡下一帧生效,在动画完成后删除

    ⚠️:v会转化为对应的transition的name值

    3)当然我们也可以自定义这六个class 可以直接在transition中设置对应的属性为对应的class名称,属性有:enter-class,enter-active-class,enter-to-class,leave-class,leave-active-class,leave-to-class

    4)在同时使用过渡和css动画的时候 可以设置type属性来制定vue内部机制监听transitioned或者animationed事件来完成过渡还是动画的监听

    5)如果需要设置对应的过渡时间,可以直接设置属性duration,可以直接接收一个数字(单位为毫秒),也可以接收一个对象{enter:1000,leave:300}

    6)也可以设置过渡的钩子函数,具体有:before-enter,enter,after-enter,enter-cancelled,before-leave,leave,after-leave,leave-cancelled

    7、vue的自定义指令?

    自定义指令分为全局指令和组件指令,其中全局指令需要使用directive来进行定义,组件指令需要使用directives来进行定义,具体定义方法同过滤器filter或者其他生命周期,具体使用方法如下:

    全局自定义指令 directive(name,{}),其中name表示定义的指令名称(定义指令的时候不需要带v-,但是在调用的时候需要哦带v-),第二个参数是一个对象,对象中包括五个自定义组件的钩子函数,具体包括:

    1. bind函数:只调用一次,指令第一次绑定在元素上调用,即初始化调用一次,

    2. inserted函数:并绑定元素插入父级元素(即new vue中el绑定的元素)时调用(此时父级元素不一定转化为了dom)

    3. update函数:在元素发生更新时就会调用,可以通过比较新旧的值来进行逻辑处理

    4. componentUpdated函数:元素更新完成后触发一次

    5. unbind函数:在元素所在的模板删除的时候就触发一次

    钩子函数对应的参数el,binding,vnode,oldnode,具体参数讲解如下:

    a、el指令所绑定的元素 可以直接操组dom元素

    b、binding一个对象,具体包括以下属性:

    1. 1)name:定义的指令名称 不包括v-

    2. 2)value:指令的绑定值,如果绑定的是一个计算式,value为对应计算结果

    3. 3)oldvalue:指令绑定元素的前一个值,只对update和componentUpdated钩子函数有值

    4. 4)expression:指令绑定的原始值 不对值进行任何加工

    5. 5)arg:传递给指令的参数

    6. 6)modifiers:指令修饰符,如:v-focus.show.async 则接收的modifiers为{show:true,async:true}

    c、vnode:vue编译生成的虚拟dom

    d、oldVnode:上一个vnode,只在update和componentUpdated钩子函数中有效

    ⚠️:如果不需要其他钩子函数,可以直接简写为:directive(“focus”,function(el,binding){})

    8、vue的实现原理?

    vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

    具体步骤:

    第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter

    这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

    第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

    第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:

    1. 1、在自身实例化时往属性订阅器(dep)里面添加自己

    2. 2、自身必须有一个update()方法

    3. 3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

    第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

    9、vue的diff算法理解?

    1)diff算法的作用:用来修改dom的一小段,不会引起dom树的重绘

    2)diff算法的实现原理:diff算法将virtual dom的某个节点数据改变后生成的新的vnode与旧节点进行比较,并替换为新的节点,具体过程就是调用patch方法,比较新旧节点,一边比较一边给真实的dom打补丁进行替换

    3)具体过程详解:

    a、在采用diff算法进行新旧节点进行比较的时候,比较是按照在同级进行比较的,不会进行跨级比较:

    b、当数据发生改变的时候,set方法会调用dep.notify通知所有的订阅者watcher,订阅者会调用patch函数给响应的dom进行打补丁,从而更新真实的视图

    c、patch函数接受两个参数,第一个是旧节点,第二个是新节点,首先判断两个节点是否值得比较,值得比较则执行patchVnode函数,不值得比较则直接将旧节点替换为新节点。如果两个节点一样就直接检查对应的子节点,如果子节点不一样就说明整个子节点全部改变不再往下对比直接进行新旧节点的整体替换

    d、patchVnode函数:找到真实的dom元素;判断新旧节点是否指向同一个对象,如果是就直接返回;如果新旧节点都有文本节点,那么直接将新的文本节点赋值给dom元素并且更新旧的节点为新的节点;如果旧节点有子节点而新节点没有,则直接删除dom元素中的子节点;如果旧节点没有子节点,新节点有子节点,那么直接将新节点中的子节点更新到dom中;如果两者都有子节点,那么继续调用函数updateChildren

    e、updateChildren函数:抽离出新旧节点的所有子节点,并且设置新旧节点的开始指针和结束指针,然后进行两辆比较,从而更新dom(调整顺序或者插入新的内容 结束后删掉多余的内容)

    10、vue组件的通信(父子组件和非父子组件)?
    父子组件通信

    传递参数可以使用props,传递函数可以直接在调用子组件的时候传递自定义事件,并使用$emit来调用,例如:

    //父组件
    <div classs="parent">
       <child @getinfo="myname" :userinfo="usermessage"></child>
     <div>
     export default {
         data(){
             return {
                 usermessage:'我是父亲'
             }
         },
         methods:{
             myname(name){
                 console.log('我的名字叫'+name)
             }
         }
     }
    
    
    //子组件
    <div classs="child">
       来源:{{userinfo}}
       <button @click="getname">显示我的名字</button>
     <div>
     export default {
         props:['userinfo'],
         methods:{
             getname(){
               this.$emit('getinfo','bilibili')
             }
         }
     }
    
    兄弟组件通信

    首先建立一个vue实例空白页(js文件)

    import Vue from 'vue'
      export default new Vue()
    

    组件a(数据发送方)通过使用 $emit 自定义事件把数据带过去

    <template>
        <div>
            <span>A组件->{{msg}}</span>
            <input type="button" value="把a组件数据传给b" @click ="send">
        </div>
    </template>
    <script>
    import vmson from "../../../util/emptyVue"
    export default {
        data(){
            return {
                msg:{
                    a:'111',
                    b:'222'
                }
            }
        },
        methods:{
            send:function(){
                vmson.$emit("aevent",this.msg)
            }
        }
    }
    </script>
    

    组件b(数据接收方)使用而通过 $on监听自定义事件的callback接收数据

    <template>
     <div>
        <span>b组件,a传的的数据为->{{msg}}</span>
     </div>
    </template>
    <script>
          import vmson from "../../../util/emptyVue"
          export default {
             data(){
                    return {
                        msg:""
                    }
                },
             mounted(){
                vmson.$on("aevent",(val)=>{//监听事件aevent,回调函数要使用箭头函数;
                   console.log(val);//打印结果:我是a组件的数据
                   this.msg = val;
                })
              }
        }
    </script>
    
    11、vue的路由模式及区别?
    hash模式在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;

    特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。

    history模式:history采用HTML5的新特性;

    提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history 模式下,前端的 URL必须和实际向后端发起请求的URL一致,否则会报404错误

    12、vue与react、angular的比较?
    Vue

    轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb;
    简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
    双向数据绑定:保留了angular的特点,在数据操作方面更为简单;
    组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势;

    视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
    虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式;
    运行速度更快:相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。

    React

    相同点:
    React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用;中心思想相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数,可以让开发者定制化地去处理需求;都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性。

    不同点:
    React采用的Virtual DOM会对渲染出来的结果做脏检查;Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作Virtual DOM。

    Angular

    相同点:
    都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。

    不同点:
    AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。

    13、vue-roter的钩子函数?

    vue路由钩子大致可以分为三类:

    全局钩子

    主要包括beforeEach和aftrEach,beforeEach函数有三个参数:
    to:router即将进入的路由对象
    from:当前导航即将离开的路由
    next:Function,进行管道中的一个钩子,如果执行完了,则导航的状态就是 confirmed (确认的);否则为false,终止导航。
    afterEach函数不用传next()函数这类钩子主要作用于全局,一般用来判断权限,以及以及页面丢失时候需要执行的操作,例如:

    //使用钩子函数对路由进行权限跳转
    router.beforeEach((to, from, next) => {
        const role = localStorage.getItem('ms_username');
        if(!role && to.path !== '/login'){
            next('/login');
        }else if(to.meta.permission){
            // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
            role === 'admin' ? next() : next('/403');
        }else{
            // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
            if(navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor'){
                Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,
                请使用更高版本的浏览器查看', '浏览器不兼容通知', {
                    confirmButtonText: '确定'
                });
            }else{
                next();
            }
        }
    })
    
    2)单个路由里面的钩子

    主要用于写某个指定路由跳转时需要执行的逻辑

    3)组件路由

    主要包括beforeRouteEnter和beforeRouteUpdate,beforeRouteLeave,这几个钩子都是写在组件里面也可以传三个参数(to,from,next),作用与前面类似.

    beforeRouteEnter(to, from, next) {
        next(vm => {
          if (
            vm.$route.meta.hasOwnProperty('auth_key') &&
            vm.$route.meta.auth_key != ''
          ) {
            if (!vm.hasPermission(vm.$route.meta.auth_key)) {
              vm.$router.replace('/admin/noPermission')
            }
          }
        })
      }
    
    14、vuex的使用?

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,具体包括:

    1)state:Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。

    2)getter:state的计算属性,类似vue的计算属性,主要用来过滤一些数据。

    3)action:actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。可以异步函数调用

    4)mutation:mutations定义的方法动态修改Vuex 的 store 中的状态或数据

    5)modules:项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

    15、vue的filter的理解与用法?

    1)全局过滤器必须写在vue实例创建之前

    Vue.filter('testfilter', function (value,text) { // 返回处理后的值
       return value+text
       })
    

    2)局部写法:在组件实例对象里挂载。

    filters: {
            changemsg:(val,text)\=>{ return val + text
            }
        }
    

    3)使用方式:只能使用在{{}}和:v-bind中,定义时第一个参数固定为预处理的数,后面的数为调用时传入的参数,调用时参数第一个对应定义时第二个参数,依次往后类推

    <h3 :title="test|changemsg(1234)">{{test|changemsg(4567)}}</h3>  
    //多个过滤器也可以串行使用  
    <h2>{{name|filter1|filter2|filter3}}</h2>
    

    4)vue-cli项目中注册多个全局过滤器写法:

    //1.创建一个单独的文件定义并暴露函数对象
    const filter1 = function (val) {
      return val + '--1'
    }
    const filter2 = function (val) {
      return val + '--2'
    }
    const filter3 = function (val) {
      return val + '--3'
    }
    
    
    export default {
      filter1,
      filter2,
      filter3
    }
    
    
    //2.导入main.js(在vue实例之前)
    import filters from './filter/filter.js'
    
    
    //3.循环注册过滤器
    Object.keys(filters).forEach(key=>{
      Vue.filter(key,filters[key])
    })
    
    16、vue的keep-alive的理解?

    keep-alive 是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染,页面第一次进入,钩子的触发顺序:created-> mounted-> activated,退出时触发 deactivated ,当再次进入(前进或者后退)时,只触发activated事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;其有几个属性如下:

    1)include - 字符串或正则表达式,只有名称匹配的组件会被缓存
    2)exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存
    3)include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、数组。当使用正则或者是数组时,要记得使用v-bind 。

    <!-- 逗号分隔字符串,只有组件a与b被缓存。-->
    <keep-alive include="a,b">
      <component></component>
    </keep-alive>
    
    
    <!-- 正则表达式 (需要使用 v-bind,符合匹配规则的都会被缓存) -->
    <keep-alive :include="/a|b/">
      <component></component>
    </keep-alive>
    
    
    <!-- Array (需要使用 v-bind,被包含的都会被缓存) -->
    <keep-alive :include="['a', 'b']">
      <component></component>
    </keep-alive>
    
    17、如何封装一个vue组件?

    根据业务需求,建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。

    准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
    准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
    封装完毕了,直接调用即可

    18、vue首屏白屏如何解决?

    1)路由懒加载
    2)vue-cli开启打包压缩 和后台配合 gzip访问
    3)进行cdn加速
    4)开启vue服务渲染模式
    5)用webpack的externals属性把不需要打包的库文件分离出去,减少打包后文件的大小
    6)在生产环境中删除掉不必要的console.log

     plugins: [
        new webpack.optimize.UglifyJsPlugin({ //添加-删除console.log
          compress: {
            warnings: false,
            drop_debugger: true,
            drop_console: true
          },
          sourceMap: true
        }),
    

    7)开启nginx的gzip ,在nginx.conf配置文件中配置

    http {  //在 http中配置如下代码,
       gzip on;
       gzip_disable "msie6"; 
       gzip_vary on; 
       gzip_proxied any;
       gzip_comp_level 8; #压缩级别
       gzip_buffers 16 8k;
       #gzip_http_version 1.1;
       gzip_min_length 100; #不压缩临界值
       gzip_types text/plain application/javascript application/x-javascript text/css
        application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
     }
    

    8)添加loading效果,给用户一种进度感受

    19、vue中的v-cloak的理解?

    使用 v-cloak 指令设置样式,这些样式会在 Vue 实例编译结束时,从绑定的 HTML 元素上被移除。

    一般用于解决网页闪屏的问题,在对一个的标签中使用v-cloak,然后在样式中设置[v-cloak]样式,[v-cloak]需写在 link 引入的css中,或者写一个内联css样式,写在import引入的css中不起作用。

    20、vue中template编译的理解?

    答:就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点),具体为:

    首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。

    另外compile还负责合并option。
    然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)

    21、v-model的理解?

    答:v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
    1)v-bind绑定一个value属性;
    2)v-on指令给当前元素绑定input事件

    22、computed和watch的用法和区别?
    computed

    1)变量不在 data中定义,而是定义在computed中,写法跟写方法一样,有返回值。函数名直接在页面模板中渲染,不加小括号 。
    2)根据传入的变量的变化 进行结果的更新。
    3)计算属性基于响应式依赖进行缓存。如其中的任意一个值未发生变化,它调用的就是上一次计算缓存的数据,因此提高了程序的性能。而methods中每调用一次就会重新计算一次,为了进行不必要的资源消耗,选择用计算属性。

    watch

    1)计算属性的时候 初始化的时候就可以被监听到并且计算 但是watch是发生改变的时候才会触发。
    2)当有一些数据需要随着其它数据变动而变动时,或者当需要在数据变化时执行异步或开销较大的操作时,使用 watch。

    总结:

    1)计算属性变量在computed中定义,属性监听在data中定义。
    2)计算属性是声明式的描述一个值依赖了其他值,依赖的值改变后重新计算结果更新DOM。属性监听的是定义的变量,当定义的值发生变化时,执行相对应的函数。

    23、$nextTick的使用?

    答:在vue中理解修改数据后,对应的dom需要一定的时间进行更新,因此为了能够准确的后去更新后的dom,可以采用延迟回调的方法进行更新dom的获取,所以出现了$nextTick来进行延迟回调。即:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

    24、data为什么是一个函数?

    答:这是有JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
    组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。

    25、vue单页面和传统的多页面区别?
    单页面应用(SPA)

    通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

    多页面(MPA)

    指一个应用中有多个页面,页面跳转时是整页刷新

    单页面的优点:

    用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。

    单页面缺点:

    不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。

    26、vue常用的修饰符?

    .stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡;
    .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
    .capture:与事件冒泡的方向相反,事件捕获由外到内;
    .self:只会触发自己范围内的事件,不包含子元素;
    .once:只会触发一次。

    27、vue更新数组时触发视图更新的方法?

    答:push();pop();shift();unshift();splice();sort();reverse()

    28、route和router的区别?
    $router

    router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性,常见的有:
    1)push:向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面

    // 字符串
       this.$router.push('home')
    // 对象
       this.$router.push({ path: 'home' })
    // 命名的路由
       this.$router.push({ name: 'user', params: { userId: 123 }})
    // 带查询参数,变成 /register?plan=123
       this.$router.push({ path: 'register', query: { plan: '123' }})
    

    2)go:页面路由跳转 前进或者后退

    // 页面路由跳转 前进或者后退
    this.$router.go(-1) // 后退
    

    3)replace:push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面,不会向 history 栈添加一个新的记录

    $route

    &dollar;route对象表示当前的路由信息,包含了当前URL解析得到的信息。包含当前的路径、参数、query对象等。
    1)&dollar;route.path:字符串,对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"。
    2)&dollar;route.params:一个 key/value 对象,包含了 动态片段 和 全匹配片段,如果没有路由参数,就是一个空对象。
    3)&dollar;route.query:一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。
    4)&dollar;route.hash:当前路由的 hash 值 (不带#) ,如果没有 hash 值,则为空字符串。
    5.&dollar;route.fullPath:完成解析后的 URL,包含查询参数和 hash 的完整路径。
    6&dollar;route.matched:数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
    7.&dollar;route.name:当前路径名字
    8.&dollar;route.meta:路由元信息

    29、vue-router实现懒加载的方式?
    vue异步组件

    vue异步组件技术 ==== 异步加载
    vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 。但是,这种情况下一个组件生成一个js文件

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

    路由懒加载(使用import)

    // 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
    /* const Home = () => import('@/components/home')
    const Index = () => import('@/components/index')
    const About = () => import('@/components/about') */
    // 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。把组件按组分块
    const Home =  () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
    const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
    const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
    
    {
      path: '/about',
      component: About
    }, {
      path: '/index',
      component: Index
    }, {
      path: '/home',
      component: Home
    }
    
    webpack的require,ensure()

    vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。

    /* 组件懒加载方案三: 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')
    }, {
      path: '/about',
      name: 'about',
      component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
    }
    
    30、delete和Vue.delete删除数组的区别?

    答:delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。Vue.delete 直接删除了数组 改变了数组的键值。

    31、路由跳转和location.href的区别?

    使用location.href='/url'来跳转,简单方便,但是刷新了页面;
    使用路由方式跳转,无刷新页面,静态跳转;

    32、vue的solt的用法?

    在子组件内使用特殊的<slot>元素就可以为这个子组件开启一个slot(插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的<slot> 标签及它的内容。

    简单说来就是:在子组件内部用 <slot></slot>标签占位,当在父组件中使用子组件的时候,我们可以在子组件中插入内容,而这些插入的内容则会替换 <slot></slot>标签的位置。

    当然:单个solt的时候可以不对solt进行命名,如果存在多个 则一个可以不命名,其他必须命名,在调用的时候指定名称的对应替换slot,没有指定的则直接默认无名称的solt

    33、$emit 、$on 、$once 、$off理解?
    $emit

    触发当前实例上的自定义事件(并将附加参数都传给监听器回调)

    $on

    监听实例上自定义事件并调用回调函数,监听emit触发的事件

    $once

    监听一个自定义事件,但是只触发一次,在第一次触发之后移除监听器。

    $off

    用来移除自定义事件监听器。如果没有提供参数,则移除所有的事件监听器;如果只提供了事件,则移除该事件所有的监听器;如果同时提供了事件与回调,则只移除这个回调的监听器。

    这四个方法的实现原理是:通过对vue实例挂载,然后分别使用对象存储数组对应的函数事件,其中emit通过循环查找存储的数组中对应的函数进行调用,once只匹配一次就就结束,on是将对应的函数存储到数组中,off是删除数组中指定的元素或者所有的元素事件。具体可以参考文章:VUE emit实现

    34、$root、$refs、$parent的使用?
    $root

    可以用来获取vue的根实例,比如在简单的项目中将公共数据放再vue根实例上(可以理解为一个全局 store ),因此可以代替vuex实现状态管理;

    $refs

    在子组件上使用ref特性后,this.属性可以直接访问该子组件。可以代替事件emit 和$on 的作用。

    使用方式是通过ref特性为这个子组件赋予一个ID引用,再通过this.$refs.testId获取指定元素。

    注意:$refs只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问$refs。

    $parent

    $parent属性可以用来从一个子组件访问父组件的实例,可以替代将数据以 prop 的方式传入子组件的方式;当变更父级组件的数据的时候,容易造成调试和理解难度增加;

    35、vue开发遇到的问题?
    1)样式污染

    答:在编写样式中,如果需要防止样式的污染,可以使用两种方式,一种是在组件的根元素上增加一个唯一的class或者id,然后在编写组件的样式时候在根元素对应的class或者id下进行编写;另一种方式是在对应的style上添加scoped关键字,不过该关键字对引用的框架UI无效

    2)router-link在安卓上不起作用

    答:不起作用的原因是因为转码编译的问题,可以使用babel来进行处理,安装babel polypill插件解决

    3)初始化页面出现闪屏乱码的问题

    答:这是因为vue还没有解析的情况下会容易出现花屏现象,看到类似于{{data}}的字样,可以使用两种方式来进行处理,一种为:在设置index.html的根元素的元素的样式为display:none,然后在mounted中的$nextTick函数中display:block展示;另一种方式是使用vue的内置指令:v-cloak,并且在css中设置样式

    [v-cloak] {  
        display: none;  
    }
    
    4)router-link上事件无效解决方法

    答:使用@click.native来进行调用原生的js事件。原因:router-link会阻止click事件,.native指直接监听一个原生事件。

    本文完〜

    展开全文
  • 2022最新前端vue面试题

    万次阅读 多人点赞 2022-03-13 22:44:53
    我叫XXX,来自XXX,很荣幸能来我们公司面试,我从事前端开发有3年了,目前掌握的技术有html,css,js,ajax,vue,小程序,参与过各种类型的项目。 我做过的项目有 A,B,C,D,E 那么最近做的一个项目是XXX 在这个项目中我主要...

    一.自我介绍

    (我是谁 来自哪里,今天来的目的,面试的岗位是什么,几年的工作经验,掌握的技术栈有哪些,开发过什么项目,项目中负责的板块是什么)

    面试官您好!我叫XXX,来自XXX,很荣幸能来我们公司面试,我从事前端开发有3年了,目前掌握的技术有html,css,js,ajax,vue,小程序,参与过各种类型的项目。
    我做过的项目有 A,B,C,D,E 那么最近做的一个项目是XXX 在这个项目中我主要负责的板块是XXX 面试官 您这边还有什么想要了解的么。

    二.项目功能提问

    vue后台项目(这几个功能点要求都能用自己的话说出来)

    1.路由守卫 / 导航守卫

    既然是守卫,首先是对咱们后台页面访问的一层保护,如果我没有进行登陆过,后台的操作页面是不允许用户访问的
    我们是用到vue路由中的一个钩子函数beforeEach,那么这个函数中有三个参数,分别是to from next
    to是去哪里 from是从哪里来 next下一步说通俗点就是放行
    主要逻辑是判断我们有没有登录,那么我们可以通过登录后获取到的token来判断 如果有token就直接next()放行
    如果没有的前提下,我们再判断用户访问的页面是不是登陆页面吗,是的话就放行 不是就跳回登录页

    token失效期,我们前端该如何处理。

    2.权限路由/动态路由/鉴权

    既然说到权限 那么肯定是根据不同账户得到不同的权限来做路由配置和菜单的渲染
    第一点当我们登录之后会获取到当前账户的身份(权限),那么我们的路由配置实际上就是一个数组
    我们要做的事情就是把获取到的身份与这个数组做对比,通过相关的计算筛选出最终匹配当前身份的路由配置
    然后将计算出来的路由数组通过router.addRouters动态挂载
    还要注意的一点就是需要将我们筛选出来的路由配置渲染到我们的前端页面上去一一相对应

    3.拦截器:请求拦截 响应拦截

    请求拦截:因为http是无状态的 无法保存我们的状态,那么我们就需要一个标识
    当我们登录之后,后续的所有请求操作都需要携带我们这个token,所以我们统一把它添加到请求头当中,避免了
    无意义请求

    响应拦截:当设置了响应拦截后所有的响应都会经过它,所以方便我们统一处理响应数据做相关的操作

    4.增 删 改 查(增加数据项)

    这些操作都是针对与数据来进行操作
    增:我们要增加一条数据或者多条数据,首先第一点我们需要获取到增加的数据,然后通过后台提供的相关接口,把数据作为参数传递,当后台拿到我的数据后往数据库中追加这些数据,然后将最新的数据响应给我们,之后再进行渲染

    删:首先获取到要删除的这条数据唯一标识可能是ID 可能是code,然后通过后台提供的相关接口,把这个标识作为参数传递,当后台拿到后就会删除这个标识相对应的数据,然后将最新的数据响应给我们,之后再进行渲染

    改:首先获取到要修改的这条数据唯一标识可能是ID 可能是code,然后前端进行数据改动,然后通过后台提供的相关接口,把数据作为参数传递,当后台拿到我的数据后往数据库中修改这个标识相对应的数据,然后将修改后的数据响应给我们,之后再进行渲染

    查:不要参数, 不需要传递任何参数,直接调用接口获取所有数据
    需要参数,首先第一点我们需要获取到需要查询的关键字然后通过后台提供的相关接口,把这些关键字作为参数传递,当后台拿到这个关键字把相对应的数据响应给我们,之后再进行渲染

    5.axios的封装

    为了方便使用我们进行了封装
    首先我们封装一个get或者post的这些方法,然后通过返回一个promise对象进行使用
    在promise中通过.then和.catch拿到axios请求结果
    然后通过工具层将不同的业务版块需要调用的接口进行模块化再暴露出去
    在我们的但页面中引入相对于的接口模块,然后调用,因为我们底层封装的是一个promise对象
    所以我们可以通过ES7中的 async await直接拿到响应数据

    三.移动端项目功能点(老师自行提问考察2-3个点)

    四.小程序功能点(考察2-3个点)

    五知识点提问:

    1.vue常用指令有哪些?

    v-for /v-bind(😃 /v-if/ v-show/ v-else-if /v-else/ v-model / v-on(@) / v-text / v-html / v-once /
    v-prev / v-cloak

    2.computed和watch的区别是什么?

    computed 一对多, 多次调用时,会把第一次调用的结果放入缓存,节约性能
    定义的函数必须要写 return,不然会报错
    调用的时候不能加括号,不然会报错
    在computed中定义一个函数(看起来是一个函数,其实是一个属性)

    watch 多对一 只监听,不会产生新的函数名,watch也可以渲染数据,但是和computed比较就比较复杂

    3.v-if 和 v-show的区别是什么? 什么时候使用v-if更好? 什么时候用v-show更好?

    v-show 可以操作display属性.主要用于频繁操作
    v-if 销毁和创建元素,主要是用于大量数据渲染到页面时使用符合条件就将数据渲染,频繁使用会消耗性能

    4.数组常用方法有哪些?

    pop/ push/ shirf/ unshirf/ reverse/ sort/ splice
    find/ findIndexOf/ indexOf / every / some / forEach / map / includes / join / concat / filter / flat /slice

    5.new操作具体干了什么?

    1. 在堆空间中创建一个对象
    2. this指向这个对象
    3. 执行构造函数的语句
    4. 返回这个对象

    6.请以自己理解讲解js堆和栈,以及深拷贝怎么解决?(重点)

    堆是用来存放引用数据类型,例如对象,数组,函数
    栈是用来存放基本数据类型,变量和引用数据类型的地址值 ; 体积小,数据经常变化
    深拷贝的解决方案 :

    1. 使用lodash 插件
    2. 使用递归解决深拷贝
    3. 如果数据中没有函数,undefined 可以使用json.stringify+json.parse实现深拷贝

    7.跨域引起的原因,以及开发时的解决方案?

    跨域: 非同源策略的就叫跨域
    同源策略就是相同的http,相同的地址,相同的端口
    解决方法: 1 nginx反向代理

    8.vue的3种组件通信方式?(重点)

    1 父子通信

    在嵌套组件中,父组件中的[子组件标签] 绑定自定义属性;
    在子组件中 props: { 子组件标签自定义的属性名: { type: , default} }

    2 子父通信

    在嵌套组件中,父组件中的[子组件标签] ,自定义事件@fn=“”,
    在子组件中,触发这个自定义事件
    . e m i t ( ′ 自定义的事件 名 ′ , 数据 ) / / 标签中的写法 t h i s . .emit('自定义的事件名',数据) //标签中的写法 this. .emit(自定义的事件,数据)//标签中的写法this.emit() // js中的写法
    在父组件的方法中 形参接收数据

    3 非父子通信(兄弟通信)

    $eventBus

    9.vue中key的唯一性的作用,以及异步加载组件的方式?

    key的唯一性可以给每一个节点有一个唯一标识,当添加或删除节点时,通过对比数据前后的变化,只用操作某个变化的节点,不需要重新渲染所有的数据,提高了性能
    异步加载组件: () => import(‘…/…/’)

    10.bfc区域的理解?

    Block Formatting context 块级格式化上下文
    成立条件有: display:inline-block 或者 position:absolute/ fixed
    常用于margin穿透,高度塌陷

    11.es6的新增特性

    箭头函数,对象属性的简写,解构赋值,模板字符串,类(类的继承),扩展运算符,模块化(moudle),promise,Async / Await (ES7),let const 块级作用域

    12.事件冒泡/捕获,以及事件委托。(重要)

    捕获: 从document开始,层层子元素传递,直到点击到当前子元素
    冒泡: 从点击当前子元素开始,层层父级传递,直到document
    事件委托: 将子元素的事件交给父元素处理(主要是添加新的节点,是无法绑定事件,这个时候需要事件委派)
    给父元素绑定事件,通过捕获的过程来获取事件,并通过etarget来获取目标元素

    13.cookie/localstorage/session区别(重要)

    localstorage 本地存储,只有手动删除才会销毁
    session数据保存在服务器端,生命周期由服务器端决定
    cookie数据保存在客户端 只有4k左右
    session和cookie 都是用来跟踪浏览器用户身份的会话方式

    14.$nextTick用过吗,有什么作用?

    视图更新之后,基于新的视图进行操作
    一般created的时候dom没有渲染,如果要操作dom,最好放在this.$nextTick(()=>{})回调函数 中完成

    15.vue-router路由的传参方式(重要)

    第一种:使用router的name属性也就是params来传递参数

    传值页面:
    this. r o u t e r . p u s h ( n a m e : " 路由配置中对应的 n a m e 名 " , p a r a m s : 参数 ) 取值页面 t h i s . router.push({name:"路由配置中对应的name名",params:{参数}}) 取值页面 this. router.push(name:"路由配置中对应的name",params:参数)取值页面this.route.params.userId

    第二种:使用query来传递参数

    传值页面
    this. r o u t e r . p u s h ( p a t h : " / l o g i n " , q u e r y : 参数 ) 取值页面 t h i s . router.push({path:"/login",query:{参数}}) 取值页面 this. router.push(path:"/login",query:参数)取值页面this.route.query.userId

    第三种:使用vue里的标签来传递参数

    传值页面
    Hi页面1
    取值页面
    this.$route.params.userId

    第四种 : 动态路由传参

    this. r o u t e r . p u s h ( ′ . / . / ′ + i d ) 取值页面 t h i s . router.push('././' + id) 取值页面 this. router.push(././+id)取值页面this.route.params.id

    16.函数的防抖和节流。(重要)

    防抖的作用是:当用户多次触发回调函数时,只触发最后一次操作的,其余的全部忽略掉;
    函数节流:是确保函数特定的时间内至多执行一次

    17.讲解下浏览器的重绘和回流(重要)

    回流 (Reflow):当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部 分或全部文档的过程称为回流。
    会导致回流的操作:
    页面首次渲染
    浏览器窗口大小发生改变
    元素尺寸或位置发生改变
    元素内容变化(文字数量或 图片大小等等)
    元素字体大小变化
    添加或者删除可见的DOM元素
    激活CSS伪类(例 如::hover)
    查询某些属性或调用某些方法

    重绘 (Repaint)
    当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称 为重绘。
    回流一定会导致重绘,重绘不一定会回流

    18.js的内存泄露,以及vue中常注意的两种(重要)

    1. 闭包
      ie9之前采用的引用计数算法
    2. 意外的全局变量

    19.请求怎么带token?(放入了哪里?每次请求前做了什么操作) (重要)

    1, 获取本地存储中的 token,并放在请求拦截器中,这样所有的请求都可以直接通过请求拦截器将token传给服务器

    20.git拿到项目地址时,到修改提交做的流程。

    1 git clone 地址
    2 git checkout -b 分支名
    3 git add .
    4 git commit -m"备注"
    5 git checkout master
    6 git merge 分支名
    7 git push origin master
    首先需要通过克隆项目地址,将项目拉取到本地仓库,创建新的分支,在分支上编写代码,写完功能后,提交并保存到本地仓库.合并分支后推送到远程仓库

    21.post和get的区别?

    1. get 的参数会显示在地址栏,不安全. 可传的数据量小
    2. post传的参数不会在地址栏显示,相对安全,可传的数据量大

    22.element表格中,如果点击拿当前行的数据怎么写?

    使用插槽的格式 v-slot={row} 就可以获取到当前行的数据

    23.思考如果要修改上传完头像后怎么,去同步通知头部的头像更新,用到组件的哪个?

    修改头像后,在header组件 created钩子中发送请求获取用户信息,

    24.promise和async/await区别,简洁讲述? (重要)

    1. promise是ES6,async/await是ES7
    2. async/await相对于promise来讲,写法更加优雅
    3. reject状态:
      1)promise错误可以通过catch来捕捉,建议尾部捕获错误,2)async/await既可以用.then又可以用try-catch捕捉

    25.get和post的区别 (重要)

    1. GET在浏览器回退时是无害的,而POST会再次提交请求
    2. GET请求会被浏览器主动cache,而POST不会,除非手动设置
    3. GET请求只能进行url编码,而POST支持多种编码方式
    4. GET请求参数会被完整保留在浏览器历史记录里,而POST的参数不会保留
    5. GET请求在URL中传送的参数有长度限制,而POST没有
    6. GET比POST更不安全,因为参数直接暴露在URl上,不能用来传递敏感信息.
    7. GET参数通过URl传递,POST参数放在Request body中
    8. 对于参数的数据类型,GET只接受ASCII字符,而POST没有限制
    9. GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

    26.vue项目中你做的优化?(重要)

    小到代码:html的结构/css的样式/js处理数据时候es6的新特性/生命周期销毁优化
    大到项目结构:模块改造/组件抽取
    vue本身:v-if和v-for的使用/build打包时/sprite精灵图

    27.mvvm和mvc区别?它和其它框架jquery的区别

    视图结构的概念区别,一个数据驱动一个事件操作,比如后者多为查找dom结构进行操作,前者为渲染时就绑定了methods方法,不用查找

    28.vue页面之间的传参(重要)

    query 地址栏显示,刷新不丢失,类似get
    params 地址栏不显示,隐藏传参,刷新丢失类似post
    /:id 动态传参,刷新不丢失同query

    29.ES6 Promise 用法,以及使用场景?

    等待接口完成,进行下一步操作用promise
    配合async和await进行,请求数据回的结构,又或者等待完成进行操作

    30.说说你们公司产品开发流程或web前端的开发流程?

    产品确定迭代需求/设计进行设计稿设计/小组会议讨论实现可行性,以及后端前端发表意见/前端写页面,后端开发接口/调试接口/自测完成给测试人员测试/上线

    31.vue的生命周期是什么?

    beforeCreate :创建vue实例 data computed watch methods不能访问;
    created: 可以对data数据进行操作, 可进行一些请求,但不易过多,避免白屏时间太长
    beforeMount:判断是否有template进行渲染保存到内存当中,但还未挂载在页面上;
    mounted: 将内存中的模块挂载到页面上 ,此时可以操作页面上的DOM节点,但还未挂载在页面上
    beforeUpdate: 页面显示的数据是旧的,此时data里的数据是最新,页面数据和data数据还没同步;
    updated : 根据data里的最新数据渲染出最新的DOM树 然后挂载到页面
    beforeDestroy:此时组件从运行进入到销毁阶段 data和methods可用 销毁还未执行;
    destroyed : 组件已经完全销毁,所有的方法指令等都不可使用

    32.插槽的作用以及使用方式?

    组件化时候,有时需要让内容显示到指定位置,用slot的写法,展示出默认内容或自定义内容。
    或者具名和匿名插槽的方式用法,具名可以指定位置

    33.vue的单项数据流?

    答:数据从父级组件传递给子组件,子组件内部不能直接修改从父级传递过来的数据。这样防止子组件意外改变父组件的状态

    34.vue中有没有用过组件通信方式 (必背)

    父传子:父组件中,子组件上通过属性绑定的方式向子中传递,子中用props接收即可
    子传父:通过 e m i t 其中有两个参数第一个作为父中的事件函数 , 第二个是要传递的数据 , 父中在触发函数的形参中拿到乱传 / 兄弟传 : 在 m a i n . j s 中先给 v u e 原型上挂载一个 v u e 实例 , 在组建中用 emit 其中有两个参数 第一个作为父中的事件函数,第二个是要传递的数据,父中在触发函数的形参中拿到 乱传/兄弟传:在main.js中先给vue原型上挂载一个vue实例,在组建中用 emit其中有两个参数第一个作为父中的事件函数,第二个是要传递的数据,父中在触发函数的形参中拿到乱传/兄弟传:main.js中先给vue原型上挂载一个vue实例,在组建中用emit来通知 o n 来监听到 on来监听到 on来监听到emit的通知即可

    35.v-on可以监听多个方法么? 要注意什么?(必背)

    可以,
    1.当没有参数传递时,方法名称后面可以不加小括号
    2.当需要传递参数时,且只有一个参数需要传递,而没有进行传递,会默认输出浏览器的event对象
    3.当需要传递多个参数时,想要获取浏览器的event对象,需要在前面加$符号

    36.vue中ref的作用是什么?(必背)

    作用一(基本用法):本页面获取dom元素
    作用二:获取子组件中的data
    作用三:调用子组件中的方法
    作用四:子组件调用父组件方法

    37.ES6的新特性有哪些?(必背)

    列举常用的ES6特性:

    1. let、const
    2. 箭头函数
    3. 类的支持
    4. 字符串模块
    5. symbols
    6. Promises
    7. 数据解构
    8. 展开运算符

    38.什么是事件委托?(必背)

    让利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!

    39.$route 和 $router 的区别?(必背)

    router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,
    例如history对象,经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。。。
    route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

    40…什么是原型链?(必背)

    答:实例对象会先查找自身有没有所需成员,如果没有就会通过proto向构造函数的prototype中查找
    如果还是没有,又会通过构造函数的prototype的proto去找到object的prototype,还是没有找到
    就会通过object的prototype的proto找到null 像这样用proto一层层往上查找的方式,称为原型链

    41.什么是递归?(必背)

    答: 函数内部自己调用自己, 这个函数就是递归函数 作用和循环效果一样,但很容易发生“栈溢出”错误,必须加退出条件return。

    42.什么是闭包?(必背)

    答: 函数嵌套函数,函数内部可以访问外部变量,外部不能直接访问该变量闭包保存了自己的私有变量,通过提供的接口给外部使用 延申了作用范围

    43.改变this 指向的方式(必背)

    答: call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向 应用场景: 经常做继承.
    apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。应用场景: 经常跟数组有关系
    bind() 方法不会调用函数,但是能改变函数内部this 指向,返回的是原函数改变this之后产生的新函数 应用场景:不调用函数,但是还想改变this指向
    如果只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind

    44.JavaScript 有几种类型(必背)

    基本数据类型:undefined、null、boolean、number、string、symbol(es6的新数据类型)
    引用数据类型:object、array、function(统称为object)

    45.组件中 data 为什么是一个函数?

    组件上的data是函数的情况下,组件每次调用data里面的数据,都是由data这个独有的函数返回过来的数据,
    所以不会造成这个组件更改data的数据,另一个在使用这个数据的组件也会更改这个数据

    46.new操作符具体干了什么呢?(必背)

    1. 创建一个空对象
    2. this指向这个对象
    3. 给这个对象添加属性和方法
    4. 返回这个对象

    47.什么是同源(必背)

    答: 同源就是两个页面有相同的协议 域名 端口 就属于同源 其中只要一个不同就不同源

    48.promise如何使用 有什么作用(必背)

    promise是es6中新增的一个构造函数,是为了解决异步操作中数据调用嵌套(回调地狱)的问题。
    promise对象提供两个方法 resolve 和 reject 那么需要拿到他们的结果 就需要用到promis对象下的then和carch

    49.JS作用域和变量提升?(必背)

    作用域:变量起作用的范围 变量访问会层层往上级作用域访问直到window,称为作用域链
    变量提升:JS编译阶段会将文件中所有var,function声明的变量提升到当前作用域最顶端

    50.为什么构造函数的方法要放在prototype里边为什么不直接用this.的方式声明?(必背)

    答:因为prototype占用一个存储空间,实例通过proto指针指向prototype,可以减少内存占用减少不必要的开销

    51.函数的防抖和节流。(必背)

    防抖函数:将多次触发变成最后一次触发
    节流函数:将多次执行变成每隔一个时间节点去执行的函数

    展开全文
  • 最全vue面试题+详解答案

    最全vue面试题+详解答案

    1、MVC 和 MVVM 区别
    MVC
    MVC全名是 Model View Controller,时模型 - 视图 - 控制器的缩写,一种软件设计典范。

    Model(模型):是用于处理应用程序数据逻辑部分。通常模型对象负责在数据库中存取数据。
    View(视图):是应用程序中处理数据显示的本分。通常视图是依据模型数据创建的。
    Controller(控制器):是应用程序处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
    在这里插入图片描述

    MVC的思想:一句话描述就是Controller负责将Model的数据用View显示出来,换句话说就是在Controller里面把Model的数据赋值给View。
    MVVM
    MVVM新增了VM类。

    ViewModel层:做了两件事达到了数据的双向绑定,一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。 实现的方式时:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转换成后端的数据。实现的方式是:DOM事件监听。
    在这里插入图片描述

    MVVM与MVC最大的区别就是:实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再手动操作Dom元素来改变View的显示。 而是改变属性后该属性对应的View层显示会自动改变(对应Vue数据驱动的思想)
    整体看来,MVVM比MVC精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也察觉不到View,这种低耦合模式提高代码的可重用性。
    注意:Vue并没有完全遵循MVVM的思想,这一点官网自己也有声明。
    在这里插入图片描述

    那么问题来了,为什么官方要说Vue没有完全遵循MVVM思想呢?
    严格的MVVVM要求View不能和Model直接通信,而Vue提供了$refs这个属性,让Model可以直接操作View,违反了这一规定,所以是Vue没有完全遵循MVVM。
    2、为什么data是一个函数
    组件的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一分新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。

    3、Vue组件通讯有哪些方式?
    1、props 和 e m i t 。 父 组 件 向 子 组 件 传 递 数 据 是 通 过 p r o p s 传 递 的 , 子 组 件 传 递 给 父 组 件 是 通 过 emit。父组件向子组件传递数据是通过props传递的,子组件传递给父组件是通过 emitpropsemit触发事件来做到的。

    2、$parent 和 $children 获取单签组件的父组件和当前组件的子组件。

    3、$attrs 和 l i s t e n e r s A − > B − > C 。 V u e 2.4 开 始 提 供 了 listeners A -> B -> C。Vue2.4开始提供了 listenersA>B>CVue2.4attrs和$listeners来解决这个问题。

    4、父组件中通过 provide 来提供变量,然后在子组件中通过 inject 来注入变量。(官方不推荐在实际业务中适用,但是写组件库时很常用。)

    5、$refs 获取组件实例。

    6、envetBus 兄弟组件数据传递,这种情况下可以使用事件总线的方式。
    加粗样式
    7、vuex 状态管理。
    加粗样式
    4、Vue的生命周期方法有哪些?一般在哪一步发送请求?
    beforeCreate 在实例初始化之后,数据观测(data observe)和 event/watcher 事件配置之前被调用。在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问。

    created 实例已经创建完成之后被调用。在这一步,实例已经完成以下的配置:数据观测(data observe ),属性和方法的运算,watch/event 事件回调。这里没有 e l , 如 果 非 要 想 与 D O M 进 行 交 互 , 可 以 通 过 v m . el,如果非要想与 DOM 进行交互,可以通过vm. elDOMvm.nextTick 来访问 DOM。

    beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。

    mounted 在挂载完成后发生,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom节点。

    beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁 (patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。

    updated 发生在更新完成之后,当前阶段组件 Dom 已经完成更新。要注意的是避免在此期间更新数据,因为这个可能导致无限循环的更新,该钩子在服务器渲染期间不被调用。

    beforeDestroy 实例销毁之前调用。在这一步,实力仍然完全可用。我们可以在这时进行 善后收尾工作,比如清除定时器。

    ***destroyed *** Vue实例销毁后调用。调用后,Vue实例指示的东西都会解绑定,所有的事件监听器会被移除,左右的子实例也会被销毁,该钩子在服务器端渲染不被调用。

    activated keep-alive 专属,组件被激活时调用

    deactivated keep-alive 专属,组件被销毁时调用

    异步请求在哪一步发起?
    可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data已经创建,可以将服务器端返回的数据进行赋值。

    如果异步请求不需要依赖 DOM 推荐加载 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:

    能更快获取到服务端数据,减少页面loading时间;
    ssr 不支持 beforeMount、mounted 钩子函数,所以放在 created 中有助于一致性。
    5、v-if 和 v-show 的区别
    v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。

    v-show 会被编译成指令,条件不满足时控制样式将此节点隐藏(display:none)

    使用场景
    v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景。
    v-show 适用于需要非常频繁切换条件的场景。
    扩展补充:display:none 、 visibility:hidden 和 opacity:0 之间的区别?
    三者公共点都是隐藏。不同点:
    一、是否占据空间。
    display:none,隐藏之后不占位置;visibility:hidden、opacity:0,隐藏后任然占据位置。
    二、子元素是否继承。
    display:none — 不会被子元素继承,父元素都不存在了,子元素也不会显示出来。
    visibility:hidden — 会被子元素继承,通过设置子元素 visibility:visible 来显示子元素。
    opacity:0 — 会被子元素继承,但是不能设置子元素 opacity:0 来先重新显示。
    三、事件绑定。
    display:none 的元素都已经不存在了,因此无法触发他绑定的事件。
    visibility:hidden 不会触发他上面绑定的事件。
    opacity:0 元素上面绑定的事件时可以触发的。
    四、过度动画。
    transition对于display是无效的。
    transition对于visibility是无效的。
    transition对于opacity是有效的。
    6、说说 vue 内置指令
    在这里插入图片描述

    ·v-once - 定义它的元素或组件只渲染一次,包括元素或组件的所有节点,首次渲染后,不再随数据的变化重新渲染,将被视为静态内容。
    ·v-cloak - 这个指令保持在元素上直到关联实例结束编译 – 解决初始化慢到页面闪动的最佳实践。
    ·v-bind - 绑定属性,动态更新HTML元素上的属性。例如 v-bind:class。
    ·v-on - 用于监听DOM事件。例如 v-on:click v-on:keyup
    ·v-html - 赋值就是变量的innerHTML – 注意防止xss攻击
    ·v-text - 更新元素的textContent
    ·v-model - 1、在普通标签。变成value和input的语法糖,并且会处理拼音输入法的问题。2、再组件上。也是处理value和input语法糖。
    ·v-if / v-else / v-else-if。可以配合template使用;在render函数里面就是三元表达式。
    ·v-show - 使用指令来实现 – 最终会通过display来进行显示隐藏
    ·v-for - 循环指令编译出来的结果是 -L 代表渲染列表。优先级比v-if高最好不要一起使用,尽量使用计算属性去解决。注意增加唯一key值,不要使用index作为key。
    ·v-pre - 跳过这个元素以及子元素的编译过程,以此来加快整个项目的编译速度。
    7、怎样理解 Vue 的单项数据流
    数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。
    注意:在子组件直接用 v-model 绑定父组件传过来的 props 这样是不规范的写法,开发环境会报警告。
    如果实在要改变父组件的 props 值可以再data里面定义一个变量,并用 prop 的值初始化它,之后用$emit 通知父组件去修改。

    8、computed 和 watch 的区别和运用的场景。
    ·computed 是计算属性,依赖其它属性计算值,并且 computed 的值有缓存,职友集当计算值变化才会返回内容,他可以设置getter和setter。
    ·watch 监听到值的变化就会执行回调,在回调中可以进行一系列的操作。
    ·计算属性一般用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。

    9、v-if 和 v-for 为什么不建议一起使用
    v-for和v-if不要在同一标签中使用,因为解析时先解析v-for在解析v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式。

    10、Vue 2.0 响应式数据的原理
    整体思路是数据劫持 + 观察者模式

    对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已存在的属性),数组则是通过重写数组来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存在它所依赖的 watcher (依赖收集)get,当属性变化后会通知自己对应的 watcher 去更新(派发更新)set。

    1、Object.defineProperty 数据劫持
    2、使用 getter 收集依赖 ,setter 通知 watcher派发更新。
    3、watcher 发布订阅模式。

    11、Vue 如何检测数组变化
    数组考虑性能原因没有用 defineProperty 对数组的每一项进行拦截,而是选择对7种数组(push,shift,pop,splice,unshift,sort,reverse)方法进行重写(AOP 切片思想)。

    所以在 Vue 中修改数组的索引和长度无法监控到。需要通过以上7种变异方法修改数组才会触发数组对应的watcher进行更新。

    12、Vue3.0 用过吗?了解多少?
    响应式原理的改变 Vue3.x 使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty。
    组件选项声明方式 Vue3.x 使用 Composition API setup是Vue3.x新增的一个选项,他是组件内使用Composition API 的入口。
    模板语法变化 slot 具名插槽语法,自定义指令v-model升级。
    其他方面的更改 Suspense支持Fragment(多个根节点)和 Protal(在dom其他部分渲染组件内容)组件,针对一些特殊的场景做了处理。基于 treeShaking 优化,提供了更多的内置功能。

    13、Vue3.0 和 2.0 的响应式原理区别
    Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达13种拦截方法。

    14、Vue的父子组件生命周期钩子函数执行顺序
    加载渲染过程
    父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
    子组件更新过程
    父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
    父组件更新过程
    父beforeUpdate -> 父updated
    销毁过程
    父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

    15、虚拟DOM是什么?有什么优缺点?
    由于在浏览器中操作DOM是很昂贵的。频繁操作DOM,会产生一定性能问题。这就是虚拟Dom的产生原因。Vue2的Virtual DOM 借鉴了开源库 snabbdom 的实现。Virtual DOM本质就是用一个原生的JS对象去描述一个DOM节点,是对真实DOM的一层抽象。
    优点:
    1、保证性能下限:框架的虚拟DOM需要适配任何上层API可能产生的操作,他的一些DOM操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的DOM操作性能要好很多,因此框架的虚拟DOM至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,既保证性能的下限。
    2、无需手动操作DOM:我们不需手动去操作DOM,只需要写好 View-Model的 代码逻辑,框架会根据虚拟DOM和数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率。
    3、跨平台:虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器端渲染、weex开发等等。
    缺点:
    1、无法进行极致优化:虽然虚拟DOM + 合理的优化,足以应对大部分应用的性能需要,但在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化。
    2、首次渲染大量DOM时,由于多了一层DOM计算,会比innerHTML插入慢。

    16、v-model 原理
    v-model 只是语法糖而已。
    v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件。
    text 和 textarea 元素使用 value property 和 input 事件;
    checkbox 和 radio 使用 checked property 和 change事件;
    select 字段将 value 作为 prop 并将 change 作为事件。
    注意:对于需要使用输入法的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。
    在普通元素上:
    input v-model=‘sth’
    input v-bind:value=‘sth’ v-on:input=‘sth = $event.target.value’

    17、v-for为什么要加key
    如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。key 是为Vue中Vnode的唯一标识,通过这个key,我们的diff操作可以更准确、更快速。
    更准确:因为带key就不是就地复用了,在sameNode函数 a.key === b.key 对比中可以避免就地复用的情况。所以更加准确。
    更快速:利用key的唯一性生成map对象来获取对应节点,比遍历方式块。

    18、Vue事件绑定原理
    原生事件绑定是通过 addEventListener 绑定给真实元素的,组件事件绑定是通过Vue自定义的$on实现的。如果要在组件上使用原生事件,需要加.native修饰符,这样就相当于在父组件中把子组件当做普通的HTML标签,然后加上原生事件。
    o n 、 on、 onemit 是基于发布订阅模式的,维护一个事件中心,on的时候将事件按名称存在事件中心里,称之为订阅者,然后emit将对应的事件进行发布,去执行事件中心里的对应的监听器。

    19、vue-router 路由钩子函数是什么?执行顺序是什么?
    路由钩子的执行流程,钩子函数种类有:全局守卫、路由守卫、组件守卫。
    完整的导航解析流程:
    1、导航被触发。
    2、在失活的组件里调用 beforeRouterLeave 守卫。
    3、调用全局的 beforeEach 守卫。
    4、在重用的组件调用 beforeRouterUpdate 守卫(2.2+)。
    5、在路由配置里面 beforeEnter。
    6、解析异步路由组件。
    7、在被激活的组件里调用 beforeRouterEnter。
    8、调用全局的 beforeResolve 守卫(2.5+)。
    9、导航被确认。
    10、调用全局的 afterEach 钩子。
    11、触发 DOM 更新。
    12、调用 beforeRouterEnter 守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。

    20、vue-router 动态路由是什么?有什么问题。
    我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment)来达到这个效果: const User = {
    template: "
    User
    “, };
    const router = new VueRouter({
    routes: [
    // 动态路径参数 以冒号开头
    { path: “/user/:id”, component: User },
    ],
    });
    问题:vue-router 组件复用导致路由参数失效怎么办?
    解决方案:
    1、通过watch监听路由参数再发请求
    watch:{
    “router”:function(){
    this.getData(this.KaTeX parse error: Expected 'EOF', got '}' at position 20: …er.params.xxx) }̲ } 2、用 :key来阻止复…route.fullPath”

    21、谈一下对 vuex 的个人理解
    vuex 是专门为 vue 提供的全局状态管理系统,用于多个组件中数据共享、数据缓存等。(无法持久化、内部内心原理是通过创造一个全局实例 new Vue)
    在这里插入图片描述

    主要包括以下几个模块:

    State:定义了应用状态的数据结构,可以在这里设置默认的初始化状态。
    Getter:允许组件从Store中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
    Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
    Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步请求。
    Module:允许将单一的 Store 拆分更多个 store 且同时保存在单一的状态树中。

    22、Vuex 页面刷新数据丢失怎么解决?
    需要做 vuex 数据持久化,一般使用本地储存的方案来保存数据,可以自己设计存储方案,也可以使用第三方插件。
    推荐使用 vuex-persist (脯肉赛斯特)插件,它是为 Vuex 持久化储存而生的一个插件。不需要你手动存取 storage,而是直接将状态保存至 cookie 或者 localStorage中。

    23、Vuex 为什么要分模块并且加命名空间?
    模块: 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能会变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

    命名空间: 默认情况下,模块内部的 action、mutation、getter是注册在全局命名空间的 — 这样使得多个模块能够对同一 mutation 或 action 做出响应。如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced:true 的方式使其成为带命名的模块。当模块被注册后,他所有 getter、action、及 mutation 都会自动根据模块注册的路径调整命名。

    24、使用过 Vue SSR 吗?说说 SSR
    SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。

    优点:
    SSR 有着更好的 SEO、并且首屏加载速度更快。
    缺点:
    开发条件会受限制,服务器端渲染只支持 beforeCreate 和 created 两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于 Node.js 的运行环境。
    服务器会有更大的负载需求。

    25、vue 中使用了哪些设计模式?
    1、工厂模式 - 传入参数即可创建实例
    虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode。
    2、单例模式 - 整个程序有且仅有一个实例
    vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉。
    3、发布-订阅模式。(vue 事件机制)
    4、观察者模式。(响应式数据原理)
    5、装饰器模式(@装饰器的用法)
    6、策略模式,策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案 - 比如选项的合并策略。

    26、你都做过哪些 Vue 的性能优化?
    这里只列举针对 Vue 的性能优化,整个项目的性能优化是一个大工程。

    对象层级不要过深,否则性能就会差。
    不需要响应式的数据不要放在 data 中(可以使用 Object.freeze() 冻结数据)
    v-if 和 v-show 区分使用场景
    computed 和 watch 区分场景使用
    v-for 遍历必须加 key,key最好是id值,且避免同时使用 v-if
    大数据列表和表格性能优化 - 虚拟列表 / 虚拟表格
    防止内部泄露,组件销毁后把全局变量和时间销毁
    图片懒加载
    路由懒加载
    异步路由
    第三方插件的按需加载
    适当采用 keep-alive 缓存组件
    防抖、节流的运用
    服务端渲染 SSR or 预渲染

    27、Vue.mixin 的使用场景和原理
    在日常开发中,我们经常会遇到在不同组件中经常用到一些相同或者相似的代码,这些代码的功能相对独立,可以通过vue 的 mixin 功能抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用 mergeOptions 方法进行合并,采用策略模式针对不同的属性进行合并。当组件和混入对象含有相同名选项时,这些选项将以恰当的方式进行“合并”。

    28、nextTick 使用场景和原理
    nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法。

    29、keep-alive 使用场景和原理
    keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

    常用的两个属性 include/exclude,允许组件有条件的进行缓存。
    两个生命周期 activated/deactivated,用来得知当前组件是否处理活跃状态。
    keep-alive 运用了 LRU 算法,选择最近最久未使用的组件予以淘汰。
    扩展补充:LRU 算法是什么?
    在这里插入图片描述

    30、Vue.set 方法原理
    了解 Vue 响应式原理的同学都知道在两种情况下修改 Vue 是不会触发视图更新的。
    1、在实例创建之后添加新的属性到实例上(给响应式对象新增属性)
    2、直接更改数组下标来修改数组的值。
    Vue.set 或者说是 $set 原理如下
    因为响应式数据 我们给对象和数组本身新增了__ob__属性,代表的是 Observer 实例。当给对象新增不存在的属性,首先会把新的属性进行响应式跟踪 然后会触发对象 ob 的dep收集到的 watcher 去更新,当修改数组索引时我们调用数组本身的 splice 方法去更新数组。

    31、Vue.extend 作用和原理
    官方解释:Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

    其实就是一个子类构造器,是Vue组件的核心api。实现思路就是使用原型继承的方法返回了 vue 的子类,并且利用 mergeOptions 把传入组件的 options 就和父类的 options 进行了合并。

    32、写过自定义指令吗?原理是什么?
    指令本质上是装饰器,是 vue 对 HTML 元素的扩展,给 HTML 元素添加自定义功能。vue 编译 DOM 时,会找到指令对象,执行指令的相关方法。

    自定义指令有五个生命周期(也叫钩子函数),分别是 bind、inserted、update、componentUpdated、unbind

    1、bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
    2、inserted:被绑定元素插入父节点时调用。
    3、update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较前后的绑定值。
    4、componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
    5、unbind:只调用一次,指令与元素解绑时调用。
    原理:
    1、在生成 ast 语法树时,遇到指令会给当前元素添加 directives 属性
    2、通过 genDirectives 生成指令代码
    3、在 patch 前将指令的钩子提取到 cbs 中,在 patch 过程中调用对应的钩子。
    4、当执行指令对应钩子函数时,调用对应指令定义方法。

    33、Vue 修饰符有哪些?
    事件修饰符
    .stop 阻止事件继续传播
    .prevent 阻止标签默认行为
    .capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理
    .self 只当在 event.target 是当前元素自身时触发处理函数
    .once 事件只会触发一次
    .passive 告诉浏览器你不想阻止事件的默认行为
    v-model 的修饰符
    .lazy 通过这个修饰符,转变为在 change 事件再同步
    .number 自动将用户输入值转化为数值类型
    .trim 自动过滤用户输入的收尾空格
    键盘事件修饰符
    .enter
    .tab
    .delete (捕获“删除”和“退格”键)
    .esc
    .space
    .up
    .down
    .left
    .right
    系统修饰符
    .ctrl
    .alt
    .shift
    .meta
    鼠标按钮修饰符
    .left
    .right
    .middle

    34、Vue 模板编译原理
    Vue 的编译过程就是将 template 转化为 render 函数的过程,分为以下三步:
    第一步是将 模板字符串转换成 element ASTs(解析器)
    第二步是对 AST 进行静态节点标记,主要用来做虚拟 DOM 的渲染优化(优化器)
    第三步是 使用element ASTs 生成 render 函数代码字符串(代码生成器)

    35、生命周期钩子是如何实现的
    Vue 的生命周期钩子核心实现是利用发布订阅模式先把用户传入的生命周期钩子订阅好(内部采用数组的方法存储)然后在创建组件实例的过程中会一次执行对应的钩子方法(发布)

    36、函数式组件使用场景和原理
    函数式组件与普通组件的区别

    1、函数式组件需要在声明组件时指定 functional:true
    2、不需要实例化,所以没有this,this通过render函数的第二个参数context代替
    3、没有生命周期钩子函数,不能使用计算属性,watch
    4、不能通过 e m i t 对 外 暴 露 事 件 , 调 用 事 件 只 能 通 过 c o n t e x t . l i s t e n e r s . c l i c k 的 方 式 调 用 外 部 传 入 的 事 件 5 、 因 为 函 数 组 件 时 没 有 实 例 化 的 , 所 以 在 外 部 通 过 r e f 去 引 用 组 件 时 , 实 际 引 用 的 是 H T M L E l e m e n t 6 、 函 数 式 组 件 的 p r o p s 可 以 不 用 显 示 声 明 , 所 以 没 有 在 p r o p s 里 面 声 明 的 属 性 都 会 被 自 动 隐 式 解 析 为 p r o p , 而 普 通 的 组 件 所 有 未 声 明 的 属 性 都 解 析 到 emit对外暴露事件,调用事件只能通过context.listeners.click的方式调用外部传入的事件 5、因为函数组件时没有实例化的,所以在外部通过ref去引用组件时,实际引用的是HTMLElement 6、函数式组件的props可以不用显示声明,所以没有在props里面声明的属性都会被自动隐式解析为prop,而普通的组件所有未声明的属性都解析到 emitcontext.listeners.click5refHTMLElement6propspropspropattrs里面,并自动挂载到组件根元素上(可以通过inheritAttrs属性禁止)
    优点:1.由于函数组件不需要实例化,无状态,没有生命周期,所以渲染性要好于普通组件2.函数组件结构比较简单,代码结构更清晰

    使用场景:

    一个简单的展示组件,作为容器组件使用 比如 router-view 就是一个函数式组件。 “高阶组件”—用于接受一个组件为参数,返回一个被包装过的组件。
    相关代码如下:

    if (isTrue(Ctor.options.functional)) {
     // 带有functional的属性的就是函数式组件 
     	return createFunctionalComponent(Ctor, propsData, data, context, children);
     } 
      const listeners = data.on; 
      data.on = data.nativeOn; 
      installComponentHooks(data); // 安装组件相关钩子 (函数式组件没有调用此方法,从而性能高于普通组件)
    

    37、能说下 vue-router 中常用的路由模式和实现原理吗?
    hash 模式
    1、location.has 的值实际就是 URL 中 # 后面的东西。它的特点在于:hash虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。

    2、可以为 hash 的改变添加监听事件

    window.addEventListener("hashchange",funcRef,false)
    

    每一次改变 hash (window.location.hash),都会在浏览器的访问历史中增加一个记录,利用hash的以上特点,就可以实现前端路由“更新视图但不重新请求页面”的功能了
    特点:兼容性好但是不美观

    history 模式
    利用 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。

    这两个方法应用于浏览器的历史记录站,在当前已有的 back、forward、go 的基础上,他们提供了对历史记录进行修改的功能。这两个方法有个共同点:当调用他们修改浏览器历史记录栈后,虽然当前 URL 改变了,但浏览器不会刷新页面,这就为单页面应用前端路由“更新视图但不重新请求页面”提供了基础

    特点:虽然美观,但是刷新会出现 404 需要后端进行配置。

    38、diff 算法了解吗?
    在这里插入图片描述

    diff算法采用同级比较。
    1、tag 标签不一致直接新节点替换旧节点。
    2、tag 标签一样。
    先替换属性
    对比子元素
    新老都有子元素,采用双指针方式进行对比
    sameVnode 判断tag和key完全相同为同一节点,进行节点复用
    头和头相等对比
    尾和尾相等对比
    头和尾相等对比
    sameVnode 的时候传入两个新老子节点patch(oldChild,newChild)
    乱序情况 – 上面的都不符合,先遍历旧子节点数组形成 key值映射的map对象。
    然后根据新子节点数组循环 按照key值和位置关系移动以及新增节点 最后删除多余的旧子节点 如果移动旧节点同样需要patch(oldChild,newChild)
    新的有子元素,老的没有子元素。-- 直接将子元素虚拟节点转化成真实节点插入即可。
    新的没有子元素,老的有子元素。 – 直接清空 innerHtml
    3、无 tag 标签 – 文本节点直接比较内容是否一致

    双向绑定
    双向绑定可以分为三个问题?
    什么是双向绑定?
    双向绑定的原理?
    如何实现双向绑定?
    Q:什么是双向绑定?
    我们先从单向绑定切入

    单向绑定非常简单,就是把 Model 绑定到 View,当我们用 JavaScript 代码更新 Model 时,View 就会自动更新

    双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了 View,Model 的数据也自动被更新了,这种情况就是双向绑定
    在这里插入图片描述

    当用户填写表单时,View 的状态就被更新了,如果此时可以自动更新 Model 的状态,那就相当于我们把 Model 和 View 做了双向绑定

    关系图如下
    在这里插入图片描述

    Q:双向绑定的原理是什么?
    我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成
    数据层(Model):应用的数据及业务逻辑
    视图层(View):应用的展示效果,各类 UI 组件
    业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来
    而上面的这个分层的架构方案,可以用一个专业术语进行称呼:MVVM

    这里的控制层的核心功能便是 “数据双向绑定” 。自然,我们只需弄懂它是什么,便可以进一步了解数据绑定的原理

    理解 ViewModel
    它的主要职责就是:

    数据变化后更新视图
    视图变化后更新数据
    当然,它还有两个主要部分组成

    监听器(Observer):对所有数据的属性进行监听
    解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数
    Q:实现双向绑定
    我们还是以 Vue 为例,先来看看 Vue 中的双向绑定流程是什么的
    new Vue()首先执行初始化,对 data 执行响应化处理,这个过程发生 Observe 中;defineReactive 时为每⼀个 key 创建⼀个 Dep 实例
    同时对模板执行编译,找到其中动态绑定的数据,从 data 中获取并初始化视图,这个过程发生在 Compile 中;初始化视图时读取某个 key,例如 name1,创建⼀个 watcher1
    同时定义⼀个更新函数和 Watcher,将来对应数据变化时 Watcher 会调用更新函数
    由于 data 的某个 key 在⼀个视图中可能出现多次,所以每个 key 都需要⼀个管家 Dep 来管理多个 Watcher;由于触发 name1 的 getter 方法,便将 watcher1 添加到 name1 对应的 Dep 中
    将来 data 中数据⼀旦发生变化,会首先找到对应的 Dep,通知所有 Watcher 执行更新函数;当 name1 更新,setter 触发时,便可通过对应 Dep 通知其管理所有 Watcher 更新
    流程图如下:
    在这里插入图片描述

    实现思路

    defineReactive 时为每⼀个 key 创建⼀个 Dep 实例
    初始化视图时读取某个 key,例如 name1,创建⼀个 watcher1
    由于触发 name1 的 getter 方法,便将 watcher1 添加到 name1 对应的 Dep 中
    当 name1 更新,setter 触发时,便可通过对应 Dep 通知其管理所有 Watcher 更新

    展开全文
  • 经典面试题: 2021Vue经典面试题总结(含答案).pdf
  • 前端Vue面试题.docx

    2021-03-30 16:34:14
    面试题分为选择题、判断题、简答题三部分,总分为100。涵盖了大部分Vue及其全家桶相关知识点。
  • 前端vue面试题知识点汇总(有答案).pdf
  • 前端Vue面试题精选,速来!!!完整版pdf.pdf
  • 2021前端vue面试题(高频)

    千次阅读 2021-07-14 13:05:27
    Vue相关 ***: (1)说一下vue最大特点是什么或者说vue核心是什么 答:vue最大特点我感觉就是“组件化“和”数据驱动“ 组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面...
  • 今天把最近的面试题目做个汇总,也给自己复个盘,由于我的技术栈主要为Vue,所以大部分题目都是Vue开发相关的。 1. 谈谈你对MVVM开发模式的理解 MVVM分为Model、View、ViewModel三者。 Model 代表数据模型,数据和...
  • 总结vue前端面试题

    2020-10-27 15:52:46
    本人总结前端vue面试,包含vue的基础,以及vue的高级和组件话开发,和vue的2.0 版本,包含vue指令,插槽路由vuex等
  • 包含vue常问面试题vue3源码学习笔记 包含react常问面试题 包含vue的react的比较
  • 2022前端面试系列——Vue面试题

    千次阅读 2022-04-27 09:04:31
    Vue 双向绑定原理 描述下 vue 从初始化页面--修改数据--刷新页面 UI 的过程? 你是如何理解 Vue 的响应式系统的? 虚拟 DOM 实现原理 既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff...
  • 前端vue经典面试题78道(重点详细简洁)

    万次阅读 多人点赞 2022-03-21 15:19:41
    2.vue面试题 1.v-show和v-if区别的区别: v-show通过css display控制显示和隐藏,v-if组件真正的渲染和销毁,而不是显示和隐藏,频繁切换状态使用v-show 否则v-if 2.为何v-for要用key 快速查找到节点,减少渲染...
  • Vue经典面试题_227题(部分题没答案).pdf_前端面试题
  • 1. v-show 与 v-if 的区别 v-show:操作...因此数据只能从一个方向来修改状态 web 前端 vue 面试题(一) web 前端 vue 面试题(二) web 前端 vue 面试题(三) web 前端 vue 面试题(四) web 前端 vue 面试题(五)
  • vue中computed和watch的区别 1.computed的用法 是一个计算属性,类似于过滤器,对绑定到view的数据进行处理。computed上面的属性不可在vue data中声明,不能做异步处理 data: { firstName: 'Foo', lastName: 'Bar' ...
  • 总结出来的Vue面试题,持续更新...
  • 2022最新的前端面试题总结(vue)

    千次阅读 2022-04-21 10:22:36
    vue面试题 帮助大家快速拿到offer
  • props $emit共同点:都是动态显示 DOM 元素 区别点:性能消耗使用场景 ...vue文件的一个加载器,将template/js/style转换为js模块用途:js可以写es6、style样式给每个dom元素加上key作为唯一标识 ,
  • 2021vue面试题及答案下载,即下即用 [完整版].pdf
  • 前端 VUE 面试题

    千次阅读 2021-01-28 22:32:36
    vuex 同步请求和异步请求 vue组件 class组件和函数式组件 vue组件传值 跨组件传值 路由实现的原理 ...vue技术栈 vuex 流程 state 属性 vue实例中如何调用vuex中的数据 vue生命周期 单页面项目..
  • 最全vue面试题+详解答案.pdf
  • 2022前端框架vue面试题pdf.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,738
精华内容 9,095
关键字:

前端vue面试题