美文网首页
框架知识 - Vue

框架知识 - Vue

作者: 木头就是我呀 | 来源:发表于2020-04-22 14:48 被阅读0次

    6 道面试题

    1. v-show & v-if 的区别
    v-show 元素在树上  只是display去控制是否显示
    v-if 元素不上树
    
    使用哪个  具体看该宿主元素是否频繁切换显示
      频繁切换:如选项卡等,使用v-show
      只显示一遍:使用v-if
    
    1. 为啥 v-for 中要用key
    因为vue使用的是虚拟dom,即vdom,且在做视图更新时是异步的,会将多次更新融合在一起,
    并比较新的vdom和已存在的vdom之间的差别,即diff算法。
    在diff算法中,key作为判断两个vnode是否一致的两个条件之一(sel&&key),
    当sel&key有一个不一样,diff算法中就认为两个节点不是一样的,就会增加新的或更新掉旧的。
    在v-for生成的元素集合中,sel肯定是一样的,所以key就作为了唯一关键判断各自的方式。
      - 如果不加key,(或者使用index - unshift()),在diff算法中的updateChildren中的sameChild方法就会认为两个
        节点是相同的,就会深度比较,深度比较的时候就会出现一些值的错误(污染),比如checkbox的选中,在
         var elm = vnode.elm = oldVnode.elm;这一步,新的vnode就会被重新赋值,产生不必要的错误。
      - 如果使用key,当unshift一个data时,每个元素都是独立的,因为key不一致,所以在updateChildren中的sameChild方法
        中就会认为是false,此时,新添加的元素对应的vnode就在oldVnodes中找不到,就会preInsert,而不会和
        原有的vnode在深度比较中污染。
    
    v-for中不适用key或者key使用不当  造成的问题:
      1. checkbox列表,选中第一项,再unshift()一个元素,此时选中的还是第一项。有问题。
    
    1. 描述Vue组件生命周期(有无父子组件的情况)

    Vue生命周期详解
    当有父子组件同时存在的时候:

     打开页面
     父:beforeCreate  created  beforeMount
     子:beforeCreate  created  beforeMount  mounted
     父:mounted
     销毁组件
     父:beforeDestroy 
     子:beforeDestroy  destroyed
     父:destroyed
    
    image.png
    1. Vue组件如何通讯
    值得学习:eventBus进行mixin模式的封装  https://juejin.im/post/5bea35acf265da614e2b9f4b
    1. 父子组件  
        父组件:声明xxx函数到子组件上   子组件通过$emit('xxx')进行触发
    2. 平行组件(层级较深的组件)
        使用自定义事件,通过公用一个new Vue() 进行使用$emit('xxx')  $on('xxx')  $('xxx')【一定记得用完销毁】
    3. 毫不相干的组件
        可以使用vuex进行状态管理
    4. 当前组件传值给后面的子孙组件
        可以使用provide/reject
        在父组件
        provide:{
          xxx:111
        }
        在子组件就可以愉快的使用了
        reject : [ 'xxx' ]
    
    1. 描述组件渲染和更新的过程
    - “组件渲染和更新的过程”  简单描述一下
          初次渲染
          1. initState -> 双向数据绑定,监听getter,setter
          2. $mount阶段,将template编译成render函数
          3. 执行render函数,读取到data中的数据,读到了,就触发了getter,读不到,就不触发(watcher)。然后生成vnode
          4. 进行patch(elem,vnode)
          
          更新
          1. 修改数据,触发属性setter
          2. 拿到收集到dep中的watcher,派发更新
          3. 触发render watcher的render回调(重新执行render函数)
          4. 生成新的vnode
          5. patch(vnode,newVNode)
    
    1. 双向数据绑定v-model的实现原理
    1. input元素的value = this.name
    2. 绑定oninput事件 this.name = $event.target.value
    3. data更新就会触发re-render
    

    一些概念

    0. 怎么理解的组件化
      - 很久之前(前后端不分离,asp、jsp、php等模板时期)就有了组件化<%@includefile="xxx" %>
      - node.js中也有组件化<%- include('xxx',{data:{}}); %>
      目前vue、react与传统组件化最大的区别:数据驱动视图
      解放对dom的操作,更关注数据、业务。
    
    ----  vue 的十分总要的三个重点:
    
     ~ 响应式   ~ 模板编译   ~ 虚拟dom
    
    1.如何理解mvvm模型
      会画出来mvvm的模型图 
    
    image.png
    3. vue的响应式
      实现原理?
      Object.defineProperty(data,()=>{})
      实现代码
    <script>
        // 更新视图
        function updateView() {
            console.log('视图更新了');
        }
    
        // 处理数组
        let newArray = Object.create(Array.prototype)
        let willMethods = ['push']
        willMethods.forEach(m=>{
            newArray[m] = function () {
                updateView()
                return Array.prototype[m].apply(this,arguments)
            }
        })
    
        // 真正监听
        function observerReal(target, key, value) {
            observer(value)
            Object.defineProperty(target, key, {
                get() {
                    return value
                },
                set(newVal) {
                    value = newVal
                    updateView()
                }
            })
        }
    
        // 判断数据类型以及是否需要监听
        function observer(obj) {
            if (obj == null || typeof obj !== 'object') {
                return
            }
    
            if(obj instanceof Array){
                obj.__proto__ = newArray
            }
    
            for (let key in obj) {
                observerReal(obj, key, obj[key])
            }
        }
    
        // 待监听的数据
        let data = {
            name: 'whh',
            age: 18,
            friends: [1, 2, 3],
            info: {
                city: 'bj'
            }
        }
    
        // 进行监听
        observer(data)
    </script>
    
    Object.defineProperty()的一些缺点?
      1. 在监听数据的时候,是一次性递归深度监听全部的,计算量大
      2. 无法监听‘新增属性’&‘删除属性’
    
    4. 虚拟DOM && diff算法
      - vdom是实现vue和React的重要基石
      - diff算法是vdom中最最核心、最关键的部分
      - render函数,类似vdom,便于理解
    
      为什么出现虚拟dom?有什么历史原因?
      - dom操作十分耗时、耗费性能
      - 将dom的一些计算,交给js去做,将最小的改动交给dom去更新
      
      翻译下面的html标签到vdom
        <div id="div1" class="container">
            <p>vdom</p>
            <ul style="font-size: 20px">
                <li>a</li>
            </ul>
        </div>
        <script>
    
        // 将上述的html标签转义为vdom
        let vdom = {
            tag:'div',
            props:{
                id:'div1',
                className:'container'
            },
            children:[
                {
                    tag:'p',
                    textNode:'vdom',
                },
                {
                    tag: 'ul',
                    props: {
                        style:'font-size:20px'
                    },
                    children:[
                        {
                            tag:'li',
                            textNode: 'a'
                        }
                    ]
                }
            ]
        }
        </script>
     
    5. 学习vdom的库是什么?
      snabbdom 库 (vue是参考的该库实现的vdom和diff)
      https://github.com/snabbdom/snabbdom
    

    简单实践snabbdom

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>snabbdom</title>
    </head>
    <body>
    <div id="container">
    
    </div>
    <button id="changeBtn">change button</button>
    
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/h.js"></script>
    
    <script>
        const snabbdom = window.snabbdom
        // 定义patch
        const patch = snabbdom.init({
            snabbdom_class,
            snabbdom_props,
            snabbdom_style,
            snabbdom_eventlisteners,
        })
    
        // 定义h
        const h = snabbdom.h
        let container = document.getElementById('container')
    
        // 生成vnode
        const vnode = h('ul#list',{},
            [
                h('li.item',{},'Item 1'),
                h('li.item',{},'Item 2')
            ]
        )
    
        patch(container,vnode)
    
        let changeBtn = document.getElementById('changeBtn')
        changeBtn.addEventListener('click',function () {
            const newVNode = h('ul#list',{},
                [
                    h('li.item',{},'Item 1.1'),
                    h('li.item',{},'Item 2')
                ]
            )
            patch(vnode,newVNode)
        })
    </script>
    </body>
    </html>
    
    6. diff算法
      找出两个vdom之间的最小区别,进行更新
    
    7. 树diff的时间复杂度
      On^3  在左边第一个节点开始,每一个节点,就遍历右边一遍,此时就是On^2,
      并且在遍历时找到差异后还要计算最小转换方式,就是On^3。1000个节点,就要遍历1亿次,算法几乎不可用。
    
      Vue和React的解决方案比较粗暴,即遍历左边的时候,同位置去右边拿值,相同就不变,
      不同就替换或删掉,一次循环就结束,即时间复杂度为On。
      - 只比较同一层级,不跨级比较
      - tag不相同,直接删掉重建,不再深度比较
      - tag和key,两者都相同,则认为是相同的节点,不再深度比较。
    
    snabbdom的patch函数的实现逻辑(diff算法的主要逻辑)
    8. vue的模板
        - 模板是什么  简单描述一下
    
          1. 模板不是html,其有指令、插值、JS表达式、能实现判断、循环
          2. html是标签语言,图灵不完备;js可以实现循环、判断,是图灵完备的语言。
          3. 因此,模板肯定是转换成js代码,才可以实现各种功能
    
        - “组件渲染和更新的过程”  简单描述一下
          初次渲染
          1. initState -> 双向数据绑定,监听getter,setter
          2. $mount阶段,将template编译成render函数
          3. 执行render函数,读取到data中的数据,读到了,就触发了getter,读不到,就不触发(watcher)。然后生成vnode
          4. 进行patch(elem,vnode)
          
          更新
          1. 修改数据,触发属性setter
          2. 拿到收集到dep中的watcher,派发更新
          3. 触发render watcher的render回调(重新执行render函数)
          4. 生成新的vnode
          5. patch(vnode,newVNode)
    
    
    vue组件渲染和更新的过程
        - vue是使用什么工具将模板编译到render函数的?
    
            vue-template-complier 工具
    
        - with语法是什么意思
        
        // 使用with,能改变{}内自由变量的查找方式
        // 将{}内自由变量,当做obj的属性去查找,找不到就报错
        let obj = {a:100,b:200}
        with (obj) {
            console.log(a); // 100
            console.log(b); // 200
            console.log(c); // 报引用错误 ReferenceError: c is not defined
        }
    
        - vue 使用vue-template-compiler 将template编译成render函数
    
            let template = `<div>{{name}}</div>`
            compile.compile(template).render
    
        - vue源码中的一些简写 -c  -s  -v
    
            -c createElement,类似于snabbdom中的h函数,返回的也是vnode
            -s toString() 转换成字符串
            -v createTextVNode 创建一个文本节点
    
        - vue渲染的时候是同步渲染还是异步渲染呢?
          
          是异步渲染。就比如:$nextTick();
          目的:汇总data的修改,一次性更新视图;减少DOM的操作次数,提升性能。
    
        - 前端路由的原理(通用)
          路由模式: hash  history
        
         -  hash的特点,即为什么hash可以作为前端路由的实现模式?
          
          1. hash的变化会触发网页的跳转,即浏览器的前进与后退(最根本)
          2. hash的变化不会刷新页面,这也是SPA项目必备的特点
          3. hash是不会提交到server端,即使强制刷新
        
          - hash路由是基于哪个事件监听实现的?
    
          window.onhashchange = function(event){}
    
          - history 简介
          1. history是一个规范的路由,跳转的时候也不刷新页面
          
          - history 的实现原理
          
          history.pushState && history.replaceState
    
          - history模式是基于哪个事件监听实现的?
           
          window.onpopstate
    
          - history为什么需要后端支持?
        
          在某个路由页面比如:www.xxx.com/user/user-detail 页面的时候,
          此时强制刷新,浏览器会向后端请求www.xxx.com/user/user-detail对应的资源,肯定没有,所以会出404错误。
          解决方案: 在后端判断一下,当前项目,无论请求什么页面,都返回index.html(原始页)页面即可
    

    Vue的面试真题演练

    1. 对mvvm的理解
    
       看图
    
    2. computed的特点
    
      - 缓存,data不变就不会重新计算
    
    3. 为何组件的data必须是一个函数
    
      - vue文件编译后  是生成一个class,在哪里用到,就new一个出来,如果data不是函数的话,那么new出来的各个对象就
        会公用一个data(在堆里找的是同一个data对象),造成污染。  
        当data是个函数的时候,在new出新组件后,由于function的缘故,会不同组件之间data的作用域,就不会形成污染。
    
    4. ajax请求应该放在哪个生命周期?
      
      mounted
      因为js是单线程的,ajax异步获取数据。
      就算放到created中,created后边要执行mount,边要发起请求,其实没必要,会让流程分支,所以建议放在mounted中。
    
    5. 怎样将组件所有的props传递给子组件?
      
      <User v-bind="$props"/>
    
    6. 如何自己实现v-model?
      
      // 子组件
      <template>
          <div>
              <input type="text" :value="name" @input="$emit('change',$event.target.value)">
          </div>
      </template>
    
      <script>
          export default {
              name: "index",
              model:{
                  prop:'name',
                  event:'change'
              },
              props:{
                  name:{
                      type:String,
                      default:()=>''
                  }
              }
          }
      </script>
    
      // 父组件
      <VModel v-model="name"></VModel>
    
    7. 多个组件有相同的逻辑,如何抽离?
      
      1.mixin  
    
    8. 何时使用异步组件?
    
      1. 加载大组件,比如编辑器..
      2. 路由异步加载
    
    9. 何时使用keep-alive
      
      1. 缓存组件,不需要重复渲染
      2. 如多个静态的tab页的切换
      3. 优化性能
    
    10. 何时使用beforeDestory
      
      1. 解绑自定义事件  event.$off
      2. 清除定时器
      2. 解绑自己定义的dom事件,比如window.scroll等,vue自带的会自己解除
    
    11. 什么是作用域插槽
      
      1. 在组件内,将一些不确定的东西交给父节点去补充,并且把渲染时的作用域内的值交出去
      // 父组件  <template v-slot='scope'>scope.xxx</template>
      // 子组件  <slot :scope='scope'>  </slot>
    
    12. vuex中的action和mutation有什么区别
      
      1. action中处理异步,mutation中不可以
      2. mutation中做原子操作
      3. action可以整合多个mutation
    
    13. 请描述响应式的原理
    
      1. 监听data变化
      2. 组件渲染和更新的流程
    
    14. vue常见性能优化
      
      1. 合理使用v-show  v-if
      2. 合理使用computed
      3. v-for中加key,以及避免和v-if一起使用(v-for优先级高,先把所有代码块都for出来,再看v-if,把不要的代码块去掉,很不优雅),
        解决方案:v-for的对象可以是computed计算后的列表,这样最好;如果实在不行,就用v-show替代v-if,可以共存。
      4. 自定义事件,dom事件及时销毁。
      5. 合理使用异步组件
      6. 合理使用keep-alive
      7. data的层级不要太深,响应式监听的时候递归时间就会长。
      8. webpack层级的优化 ... 待补充
      9. 前端通用性能优化,图片懒加载等等...
    
    # 前端通用性能优化
    原则: 空间换时间
        1. 多使用内存,缓存或者其他方法
        2. 减少CPU的计算量,减少网络加载耗时
    从何入手:
        让加载更快
            减少资源体积 - 压缩代码
            减少访问次数
                合并代码(合并js等资源)
                SSR服务端渲染(把资源在后端一次组装完成,减少客户端的请求次数)
                缓存(静态资源加hash后缀,根据文件计算hash。文件不变,则会自动触发http缓存机制,返回304)
            使用更快的网络 - CDN
        让渲染更快
            CSS放在head,JS放在body最下面
            尽早开始执行JS,在DOMContentLoaded触发
            懒加载(图片懒加载,上滑加载更多...)
            对DOM查询进行缓存
            避免频繁的DOM操作,使用DocumentFragement片段
            节流、防抖
    

    相关文章

      网友评论

          本文标题:框架知识 - Vue

          本文链接:https://www.haomeiwen.com/subject/wovyihtx.html