前端面试题之 Vue

  1. 谈谈对 MVVM 的认识。

    • MVVM 分为 Model、View、ViewModel 三者:
      • Model:代表数据模型,数据和业务逻辑都在 Model 层中定义
      • View:代表 UI 视图,负责数据的展示
      • ViewModel:就是与界面(view)对应的 Model。因为,数据库结构往往是不能直接跟界面控件一一对应上的,所以,需要再定义一个数据对象专门对应 view 上的控件。而 ViewModel 的职责就是把 model 对象封装成可以显示和接受输入的界面数据对象
    • Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步
    • 简单来说,ViewModel 就是 View 与 Model 的连接器,View 与 Model 通过 ViewModel 实现双向绑定
  2. Vue 框架主要的优点是什么?

    • 渐进式构建能力是 vue.js 最大的优势,vue 有一个简洁而且合理的架构,使得它易于理解和构建
    • vue 有一个强大的充满激情人群的社区,这为 vue.js 增加了巨大的价值,使得为一个空白项目创建一个综合的解决方案变得十分容易
  3. 列举 Vue 中常见的指令及其作用。

    • 文本插值:{{ }} Mustache
      •   <div id="app">
              {{ message }}
          </div>
        
    • DOM 属性绑定: v-bind
      •   <div id="app-2">
              <span v-bind:title="message">
                  鼠标悬停几秒钟查看此处动态绑定的提示信息!
              </span>
          </div>
        
    • 指令绑定一个事件监听器:v-on
      •   <div id="app-5">
             <p>{{ message }}</p>
             <button v-on:click="reverseMessage">逆转消息</button>
          </div>
        
    • 实现表单输入和应用状态之间的双向绑定:v-model
      •   <div id="app-6">
              <p>{{ message }}</p>
              <input v-model="message">
          </div>
        
    • 控制切换一个元素的显示:v-if 和 v-else
      •   <div id="app-3">
              <p v-if="seen">现在你看到我了</p>
          </div>
        
    • 列表渲染:v-for
      •   <div id="app-4">
              <ol>
                  <li v-for="todo in todos">
                      {{ todo.text }}
                  </li>
              </ol>
          </div>
          var app4 = new Vue({
              el: '#app-4',
              data: {
                  todos: [
                      { text: '学习 JavaScript' },
                      { text: '学习 Vue' },
                      { text: '整个牛项目' }
                  ]
              }
          })
        
    • 根据条件展示元素:v-show
      •   <h1 v-show="ok">Hello!</h1>
        
      • 带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 是简单地切换元素的 CSS 属性 display
      • 注意:v-show 不支持 <template> 语法,也不支持 v-else
    • v-if 与 v-show
      • v-if 是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
      • v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
      • 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
      • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件不太可能改变,则使用 v-if 较好
    • v-if 与 v-for 一起使用
      • 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级
  4. v-ifv-show的区别是什么?

    • 区别
      • v-if
        • 动态的向 DOM 树内添加或者删除 DOM 元素;“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;在初始渲染条件为假时,什么也不做
      • v-show
        • 通过设置 DOM 元素的 display 样式属性控制显示和隐藏;不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
      • 总结:v-if 有更高的切换消耗;v-show 有更高的初始渲染消耗
    • 应用场景
      • v-if 适合运行条件很少改变的情况; v-show 适合频繁切换的情况
      • 对于管理系统权限列表的展示,这里可以使用 v-if 来渲染,如果使用 v-show,对于用户没有的权限,在网页的源码中,仍然能够显示
      • 特殊情况:在 el-table 中控制某列的显示与隐藏只能使用 v-if
  5. v-for中为什么要绑定 key?

    • 一句话来说: key 值是为了虚拟 dom 的比对
    • 展开来说: 页面上的标签都对应具体的虚拟 dom 对象(虚拟 dom 就是 js 对象), 循环中如果没有唯一 key , 页面上删除一条标签, 由于并不知道删除的是那一条! 所以要把全部虚拟 dom 重新渲染, 如果知道 key 为 x 标签被删除掉, 只需要把渲染的 dom 为 x 的标签去掉即可!
  6. 谈谈 Vue 的响应式原理(双向绑定原理)。

    • 响应式原理
      • 利用了数据劫持和订阅发布的模式, 当数据模型发生改变的时候, 视图就会响应的进行更新, 那么深入响应式原理是利用 es5 的 Object.defineProperty 中个 getter/setter 来进行数据的劫持的
    • vue 双向数据绑定原理
      • 效果
        • 数据改变 , 视图更改
        • 视图改变, 数据更改
      • 实现
        • 使用 v-model 实现
      • 缺点
        • v-model 默认绑定 value 属性, 所以 v-model 只能在表单使用
      • 原理
        • 数据能直接在视图显示的原因
          • v-model 默认绑定了 DOM 对象的 value 属性, 当它初次绑定的时候,就会触发 getter,watcher 就会触发, watcher 通知 Vue 生成新的 VDOM 树,再通过 render 函数进行渲染,生成真实 DOM
        • 视图修改数据就会修改的原因
          • 当视图修改时, 意味着 DOM 的 value 属性值改变,就会触发 setter,watcher 监听机制就会执行,watcher 通知 Vue 生成新的 VDOM 树,再通过 render 函数进行渲染,生成真实 DOM
  7. 谈谈对 虚拟 dom(vdom) 和 diff 算法 的认识。

    • 虚拟 DOM
      • 虚拟DOM 利用了 js 对象的 object 的对象模型来模拟真实 DOM,结构是树形结构
      • 优点:速度比操作真实DOM快。
      • 缺点:
        1. 更多的功能意味着更多的代码。幸运的是 Vue.js 2.0 仍然是相当小的(21.4kb 当前版本)。
        2. 虚拟DOM需要在内存中的维护一份 DOM 的副本。在 DOM 更新速度和使用内存空间之间取得平衡。
      • 应用场景
        • 虚拟 DOM 不是适合所有情况,如果虚拟 DOM 大量更改,这是合适的。But ……如果单一的,频繁的更新的话,虚拟 DOM 将会花费更多的时间处理计算的工作。
        • 所以,如果你有一个 DOM 节点相对较少页面,用虚拟 DOM,它实际上有可能会更慢。 但对于大多数单页面应用,这应该都会更快。
    • diff 算法
      • diff 算法是用来比较两个或是多个文件,返回值是文件的不同点
      • diff 算法是同级比较的,diff 思维也是来自后端
      • diff 算法的比较思维
        • 比较后会出现四种情况:
          1. 此节点是否被移除 -> 添加新的节点
          2. 属性是否被改变 -> 旧属性改为新属性
          3. 文本内容被改变-> 旧内容改为新内容
          4. 节点要被整个替换 -> 结构完全不相同 移除整个替换
    • 整个 VDOM 的使用流程(Vue)
      1. 创建 VDOM 树
      2. 利用 render 函数渲染页面
      3. 数据改变,生成新的 VDOM
      4. 通过 diff 算法比较 新、旧两个 VDOM,将不同的地方进行修改,相同的地方就地复用,最后再通过 render 函数渲染页面
  8. <keep-alive>组件有什么作用?

    • 主要用于保留组件状态或避免重新渲染
    • 比如: 有一个列表页面和一个 详情页面,那么用户就会经常执行打开详情 => 返回列表 => 打开详情这样的话 列表 和 详情 都是一个频率很高的页面,那么就可以对列表组件使用 <keep-alive></keep-alive> 进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
    • 注意:<keep-alive> 是用在其一个直属的子组件被开关的情形。如果你在其中有 v-for ,则不会工作。如果有多个条件性的子元素,<keep-alive> 要求同时只有一个子元素被渲染
  1. 请详细说明你对 Vue 的生命周期的理解。

    • 总共分为 8 个阶段创建前/后,载入前/后,更新前/后,销毁前/后
    • 创建前/后: 在 beforeCreated 阶段,vue 实例的挂载元素 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 结构依然存在
  2. methodscomputedwatch有什么区别?、

    • computed 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用,要 return 出去一个值
    • methods 方法表示一个具体的操作,主要书写业务逻辑
    • watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是 computedmethods 的结合体,有 newVal 和 oldVal 两个参数
    • 三者比较:
      • 相同点:都是一个 function
      • 不同点:
        • computed 要 return 出去一个值,watch 不用
        • methods 里的 function 更侧重业务逻辑(大量)的处理,computed 里的 function 不适合做大量业务逻辑
      • 使用场景:
        • watch:适合监听一些虚拟的东西,如路由
        • methods:适合做一些方法的调用
        • computed:可能需要引用一些数据,经过一系列的操作返回一个新的数据
  3. vm.$nextTick()方法有什么用?

    • nextTick(),是将回调函数延迟在下一次 dom 更新数据后调用。简单的理解是:当数据更新了,在 dom 中渲染后,自动执行该函数
    • 注意:Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用nextTick,则可以在回调中获取更新后的 DOM
    • 需要用 Vue.nextTick() 的地方
      1. Vue 生命周期的 created() 钩子函数进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中,原因是在 created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick() 的回调函数中。与之对应的就是 mounted 钩子函数,因为该钩子函数执行时所有的DOM挂载已完成
        •   created(){
                let that=this;
                that.$nextTick(function(){  //不使用this.$nextTick()方法会报错
                that.$refs.aa.innerHTML="created中更改了按钮内容";  //写入到DOM元素
            });
          
        }
      2. 当项目中你想在改变 DOM 元素的数据后基于新的 dom 做点什么,对新 DOM 一系列的 js 操作都需要放进 Vue.nextTick() 的回调函数中;通俗的理解是:更改数据后当你想立即使用 js 操作新的视图的时候需要使用它,即vue 改变 dom 元素结构后使用 vue.$nextTick() 方法来实现 dom 数据更新后延迟执行后续代码
        •   changeTxt:function(){
                let that=this;
                that.testMsg="修改后的文本值";  //修改dom结构
          
                that.$nextTick(function(){  //使用vue.$nextTick()方法可以dom数据更新后延迟执行
                    let domTxt=document.getElementById('h').innerText; 
                    console.log(domTxt);  //输出可以看到vue数据修改后并没有DOM没有立即更新,
                    if(domTxt==="原始值"){
                        console.log("文本data被修改后dom内容没立即更新");
                    }else {
                        console.log("文本data被修改后dom内容被马上更新了");
                    }
                });
            }
          
      3. 在使用某个第三方插件时 ,希望在 vue 生成的某些 dom 动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法
  4. 谈谈对前端路由的认识。

    • 在 Ajax 出现之前,都是使用后端路由来控制页面的渲染,服务器在接收到不同的url地址后,服务器通过解析 url 去拼接不同的 html,然后返回给前端进行渲染,所以这也是后端路由的一个弊端,每一次的切换都是需要刷新整个页面,同时如果是大量的页面每一个页面都需要做一段逻辑处理也造成了后端实在不堪重负
    • 前端路由的出现很好的解决了这个问题,前端路由不需要刷新整个页面,也就不会出现每一次切换都会出现闪烁,也没有网络延迟,大大提升了用户体验,减轻了服务器的压力,但是同时也存在问题是前端的安全性问题
    • 目前前端路由的实现主要采用两个方法:hash, history
    • 前端路由的实现方式
      1. 基于 hash,利用 href 或者 location.hash = xxx
      2. 基于 History API,主要利用 history.pushState() 和 history.repalceState()
      3. 各种 Router 框架,例如 react-router,vue-router...
  5. history模式和hash模式有什么区别?

    • hash 模式
      • hash 模式背后的原理是 onhashchange 事件,可以在 window 对象上监听这个事件
      • 因为 hash 发生变化的 url 都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了。这样一来,尽管浏览器没有请求服务器,但是页面状态和 url 一一关联起来,后来人们给它起了一个霸气的名字叫前端路由,成为了单页应用标配
      • 网易云音乐,百度网盘就采用了hash路由,看起来就是这个样子: http://music.163.com/#/friendhttps://pan.baidu.com/disk/home#list/vmode=list
    • history 模式
      • 随着 history api 的到来,前端路由开始进化了,前面的 hashchange,你只能改变 # 后面的 url 片段,而 history api 则给了前端完全的自由
      • history api可以分为两大部分,切换和修改,参考MDN,切换历史状态包括back、forward、go 三个方法,对应浏览器的前进,后退,跳转操作,有同学说了,(谷歌)浏览器只有前进和后退,没有跳转,嗯,在前进后退上长按鼠标,会出来所有当前窗口的历史记录,从而可以跳转(也许叫跳更合适)
      • 修改历史状态包括了 pushState,replaceState 两个方法,这两个方法接收三个参数: stateObj,title,url
      • 通过 history api,我们丢掉了丑陋的 #,但是它也有个问题:不怕前进,不怕后退,就怕刷新 f5,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的,不玩虚的。 在 hash 模式下,前端路由修改的是 # 中的信息,而浏览器请求时是不带它玩的,所以没有问题.但是在 history 下,你可以自由的修改 path,当刷新时,如果服务器中没有相应的响应或者资源,会分分钟刷出一个 404 来
  6. vuex 是什么,包含哪几个部分?

    • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新
    • 不能直接改变 store 中的状态。改变 store 中状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用
    • 每一个 Vuex 应用的核心就是 store(仓库)。store 基本上就是一个容器,它包含着你的应用中大部分的状态 (state)
    • VueX 是一个集中式的存储仓库【状态】,类似于 本地存储、数据库,vuex是vue的状态管理工具,它的功能主要是实现多组件间的状态【数据】共享
    • VueX 的组成部分:
      • state 状态
      • action 动作(业务交互)
      • type 要求是一个常量,理由:常量比较稳定,安全性高
      • mutation 修改 state
      • getter 获取数据
      • store state 数据存储者
  7. Vue中组件传值有哪几种方式?(兄弟、父子、子父、祖孙组件间传值各用什么?)

    • 父向子传值
      • 父子传值一般在子组件上绑定自定义的属性,然后子组件在实例中通过 props 接收该属性
    • 子向父传值
      • 这种情况一般使用emit反向传值,通过注册自定义事件,在事件函数中接收值
    • 兄弟传值
      • 子传给父,父再传给子
    • 后代(祖孙)传值
      • provide:相当于分享自己实例中的一些东西出去
      • inject :用来接受 provide 分享出去的东西
      • 父组件 provide 出去的东西,只要下面的后代组件 inject 一下就能拿到,无视组件距离
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容

  • AngularJS是什么? AngularJs(简称ng)是一个用于设计动态web应用的结构框架。首先,它是一个框...
    强哥科技兴阅读 1,250评论 0 1
  • vue是什么? vue是构建数据驱动的web界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现...
    九四年的风阅读 8,689评论 2 131
  • 借鉴别人 1,对MVC 、MVVM、MVP的理解 (1)MVC Models: 数据层,负责数据的请求和存储以及处...
    小程要谦虚阅读 754评论 0 8
  • 成王败寇,赢者通吃,在游戏盘口上除了赢就是输,没有第三种可能。 我们一直都在追求赢的路上,在学校比成绩,社会比工作...
    殷勤说阅读 572评论 0 1
  • 连续两天的加班,很疲惫,心力交瘁,所幸终于结束。偏偏又听到一个麻烦的事,算了算了,我也是不理罢了,暂时放一放...
    寒梅枝头傲阅读 324评论 0 6