vue

作者: 岚平果 | 来源:发表于2021-02-23 17:02 被阅读0次
    vue组件与实例的关系
    Vue是由一个个实例构建而成的,一个组件就是一个Vue的实例,每个组件内部都可以写属性,
    因此每一个组件都是一个Vue的实例。”
    

    0. 谈谈 vue 和 react ?

    一、两者的本质区别
    1. vue - 本质是 MVVM 框架,由 MVC 发展而来
    2. React - 本质是前端组件化框架,由后端组件化发展而来
    3. vue - 使用模板(最初由 angular 提出)
    4, React - 使用 JSX(jsx不是react独有的,已经成了一种标准)
    5. React 本身就是组件化,没有组件化就不是 React
    6. vue 也支持组件化,不过是在 MVVM 上的扩展
    
    二、两者共同点
    1. 都支持组件化
    2. 都是数据驱动视图
    

    1.mvvm 框架是什么
    答:vue是实现了双向数据绑定的mvvm框架,当视图改变更新模型层,当模型层改变更新视图层。在vue中,使用了双向绑定技术,就是View的变化能实时让Model发生变化,而Model的变化也能实时更新到View。

    0-0. vue中页面跳转传值的几种方式

    URL路径:http://localhost:8081/#/test?userid=1
    
    <router-link :to="{path:'/test',query: {userid: id}}">跳转</router-link>
    1
    收:
    
    var id = this.$route.query.userid
    1
    注意:
    to前面一定要加 : ,一定要记得加!记得加!加!
    to后面 { 中的name值(这里是userid)要与路由中的name值一致
    
    二、this.$router.push()
    1、使用path+query
    URL路径:http://localhost:8081/#/selectCate?userid=1
    
    发:
    
    var id = 1;
    this.$router.push({path:'/selectCate',query:{userid:id}});
    1
    2
    收:
    
    var id = this.$route.query.userid;
    1
    这里注意接收到的是字符串,但id是数字,所以需要转化一下:
    
    var id = parseInt(this.$route.query.userid);
    1
    2、使用name+params
    URL路径:`http://localhost:8081/#/selectCate
    
    发:
    
    var id = 1;
    this.$router.push({name:'selectCate',params:{userid:id}});
    1
    2
    收:
    
    var id = this.$route.params.userid;
    1
    总结:使用query,传输的值会在url后面以参数的形式显示出来,可以刷新页面,
    数据不变,而params不会,一刷新传的值就没了
    
    
    

    1. 谈谈你对 MVVM 开发模式的理解?

    1. MVVM 分为 Model、View、ViewModel 三者。
    2. Model 代表数据模型,数据和业务逻辑都在 Model 层中定义;
    3. View 代表 UI 视图,负责数据的展示;
    4. ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
    
    5. Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的, 
       Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的 数据改变时会触发 View 
       层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
    6. 这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注 
       对数据的维护操作即可,而不需要自己操作 dom。
    

    2. v-if 和 v-show 有什么区别?

    1. v-if 是真正的条件渲染,会控制这个 DOM 节点的存在与否
    2. v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于
       CSS 的 “display” 属性进行切换
    
    3. 当我们需要经常切换某个元素的显示/隐藏时,使用 v-show 会更加节省性能上的开销;
       当只需要一次显示或隐藏时,使用 v-if 更加合理。
    

    3. 你使用过 Vuex 吗?

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心
    就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
    
    (1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态
        发生变化,那么相应的组件也会相应地得到高效更新。
    
    (2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。 
         这样使得我们可以方便地跟踪每一个状态的变化。
         this.$store.commit('updateBusinessobj', obj);
    
    主要包括以下几个模块:
    1. State => 基本数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态。
    
    2. Getter => 从基本数据派生的数据,允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅
       是将 store 中的 getter 映射到局部计算属性。
    
    3. Mutation => 是唯一更改 store 中状态的方法,且必须是同步函数。
    
    4. Action => 像一个装饰器,包裹mutations,使之可以异步。用于提交 mutation,而不是直接
       变更状态,可以包含任意异步操作。
    
    5. Module => 模块化Vuex,允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
    
     created () {
            //在页面加载时读取sessionStorage里的状态信息
            if (sessionStorage.getItem("store")) {
                this.$store.replaceState(Object.assign({}, 
                this.$store.state, JSON.parse(sessionStorage.getItem("store"))))
            }
    
            //在页面关闭刷新时将vuex里的信息保存到sessionStorage里
            window.addEventListener("beforeunload", () => {
                sessionStorage.setItem("store", JSON.stringify(this.$store.state))
            })
    },
    
    3-1、vuex中mutation和action的详细区别
    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      },
      actions: {
        increment (context) {
          context.commit('increment')
        }
      }
    })
    1、流程顺序
    “相应视图—>修改State”拆分成两部分,视图触发Action,Action再触发Mutation。
    
    2、角色定位
    基于流程顺序,二者扮演不同的角色。
    Mutation:专注于修改State,理论上是修改State的唯一途径。
    Action:业务代码、异步请求。
    
    3、限制
    角色不同,二者有不同的限制。
    Mutation:必须同步执行。
    Action:可以异步,但不能直接操作State。
    
    总结:
    action的功能和mutation是类似的,都是去变更store里的state,不过action和mutation有两点不同:
    1、action主要处理的是异步的操作,mutation必须同步执行,而action就不受这样的限制,也就是说
    action中我们既可以处理同步,也可以处理异步的操作
    2、action改变状态,最后是通过提交mutation
    

    4. 说说你对 SPA 单页面的理解,它的优缺点分别是什么?

    首先:SPA的英文是single-page application ,整个项目中只有一个页面。其次,单页面的实现思路:
    就是在 Web 页面初始化时加载所有的 HTML、JavaScript 和 CSS,页面的内容的变化,靠动态创建dom。
    也就是一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新请求(加载)或跳转;取而代之
    的是利用路由机制实现 HTML 内容的动态变换,UI 与用户的交互,避免页面的重新加载。
    
    优点:
    1. 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
    
    2. 基于上面一点,SPA 对服务器的压力小;
    
    3. 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
    
    缺点:
    1. 初次加载耗时多,为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将
     JavaScript、CSS 统一加载,部分页面按需加载;
    
    2. 前进后退路由管理,由于单页应用在一个页面中显示所有的内容,所以不能使用
    浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
    
    3. SEO 难度较大,由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势
    

    5. Class 与 Style 如何动态绑定?

    一、Class 可以通过对象语法和数组语法进行动态绑定:
    1. 对象语法:
    <div :class="{ active: isActive, 'text-danger': hasError }"></div>
    data: {
        isActive: true,
        hasError: false
    }
    
    2.数组语法:
    <div :class="[isActive ? activeClass : '', errorClass]"></div>
    data: {
      activeClass: 'active',
      errorClass: 'text-danger'
    }
    
    二、Style 也可以通过对象语法和数组语法进行动态绑定
    1. 对象语法:
    <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
    data: {
      activeColor: 'red',
      fontSize: 30
    }
    
    2.数组语法:
    <div :style="[styleColor, styleSize]"></div>
    data: {
      styleColor: {
         color: 'red'
       },
      styleSize:{
         fontSize:'23px'
      }
    }
    

    6. 怎样理解 Vue 的单向数据流?

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到
    子组件中,但是反过来则不行。
    
    这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
    
    额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
    这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
    子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
    

    7. computed 和 watch 的区别和运用的场景?

    computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值
               发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
    watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,
            每当监听的数据变化时都会执行回调进行后续操作;
    
    运用场景:
    当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的
    缓存特性,避免每次获取值时,都要重新计算;
    
    当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们
    执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,
    并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
    

    8. 直接给一个数组项赋值,Vue 能检测到变化吗?

    由于 JavaScript 的限制,vue故意屏蔽了这些赋值响应,为了提供性能提高,Vue 不能检测到
    以下数组的变动:
    当你利用索引直接设置一个数组项时,
    例如:vm.items[indexOfItem] = newValue
    
    当你修改数组的长度时,
    例如:vm.items.length = newLength
    
    
    为了解决第一个问题,Vue 提供了以下操作方法:
    // Vue.set
    Vue.set(vm.items, indexOfItem, newValue)
    // vm.$set,Vue.set的一个别名
    vm.$set(vm.items, indexOfItem, newValue)
    // Array.prototype.splice
    vm.items.splice(indexOfItem, 1, newValue)
    
    为了解决第二个问题,Vue 提供了以下操作方法:
    vm.items.splice(newLength)
    

    8-1. Vue 怎么用 vm.$set() 解决对象新增属性不能响应的问题 ?

    1. 如果目标是数组,直接使用数组的 splice 方法触发相应式;
    
    2. 如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,
    则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化
    对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)
    

    9. 谈谈你对 Vue 生命周期的理解?

    1. 生命周期是什么?
    vue 生命周期是指 vue 实例对象从创建之初到销毁的过程, vue 所有功能的实现都是围绕它的
    生命周期进行的, 在生命周期的不同阶段调用对应的钩子函数实现组件 数据管理 和 DOM 渲染 
    两大重要功能。
    
    2. 生命周期的作用是什么?
    它的生命周期中有多个事件钩子,让我们在控制整个 Vue 实例的过程时更容易形成好的逻辑。
    
    
    生命周期                描述
    beforeCreate          组件实例被创建之初,组件的属性生效之前
    created               组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用
    beforeMount           在挂载开始之前被调用:相关的 render 函数首次被调用
    mounted               el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子
    beforeUpdate          组件数据更新之前调用,发生在虚拟 DOM 打补丁之前
    updated               组件数据更新之后
    activited             keep-alive 专属,组件被激活时调用
    deadctivated          keep-alive 专属,组件被销毁时调用
    beforeDestory         组件销毁前调用
    destoryed             组件销毁后调用
    
    1、beforeCreate 此时$el、data 的值都为undefined
    2、创建之后,此时可以拿到data的值,但是$el依旧为undefined
    3、mount之前,$el的值为“虚拟”的元素节点
    4、mount之后,mounted之前,“虚拟”的dom节点被真实的dom节点替换,并将其插入到dom树中,
     于是在触发mounted时,可以获取到$el为真实的dom元素()
    myVue.$el===document.getElementById("app-8")  // true
    
    
    
    挂载阶段(
    beforeCreate:此阶段为实例初始化之后,此时数据观察和事件机制还没有形成,不能获取到dom节点;
    created:此阶段的vue实例已经创建,仍不能获取DOM 节点.把vue 的一个实例给初始化了,
    只是存在于 js 内存的一个变量而已,这个时候并没有开始渲染;
    beforeMount:在这一阶段,我们虽然还不能获取到具体 DOM 元素,但 vue 挂载的根节点已经创建,
    下面 vue 对DOM 的操作将围绕这个根元素继续进行,beforeMount 这个阶段是过渡性的,
    一般一个项目只能用到一两次;
    mounted:组件真正绘制完成了,页面已经渲染完了,数据和DOM 都已被渲染出来,一般我们的
    异步请求都写在这里)
    
    更新阶段(
    beforeUpdate: 这一阶段,vue遵循数据驱动DOM 的原则,beforeUpdate 函数在数据更新后
    没有立即更新数据,但是DOM 数据会改变,这是双向数据绑定的作用;
    updated:这一阶段,DOM 会和更改过的内容同步)
    
    销毁阶段(
    beforeDestroy:在上一阶段vue已经成功通过数据驱动DOM 的修改,当我们不再需要 vue 操纵 DOM 时,
    就要销毁 vue,也就是清除vue 实例与 DOM 的关联,调用destroy方法可以销毁当前组件。
    在销毁前,会触发 beforeDestroy 钩子函数;
    destroyed:在销毁后,会触发destroyed 钩子函数)
    
    image.png

    10. Vue 的父组件和子组件生命周期钩子函数执行顺序?

    Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
    1. 加载渲染过程 :
    父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate ->
    子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
    
    2. 子组件更新过程 :
    父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
    
    3. 父组件更新过程 :
    父 beforeUpdate -> 父 updated
    
    4. 销毁过程 :
    父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
    

    11.父组件可以监听到子组件的生命周期吗?

    比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,
    可以通过以下写法实现:
    // Parent.vue
    <Child @mounted="doSomething"/>
    
    // Child.vue
    mounted() {
      this.$emit("mounted");
    }
    
    以上需要手动通过 $emit 触发父组件的事件,更简单的方式可以在父组件引用子组件时通过 @hook 
    来监听即可,如下所示:
    //  Parent.vue
    <Child @hook:mounted="doSomething" ></Child>
    
    doSomething() {
       console.log('父组件监听到 mounted 钩子函数 ...');
    },
    
    //  Child.vue
    mounted(){
       console.log('子组件触发 mounted 钩子函数 ...');
    },    
    // 以上输出顺序为:
    // 子组件触发 mounted 钩子函数 ...
    // 父组件监听到 mounted 钩子函数 ...
    
    
    当然 @hook 方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:
    created,updated 等都可以监听。
    

    12. 谈谈你对 keep-alive 的了解?

    keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:
    
    一般结合路由和动态组件一起使用,用于缓存组件;
    提供 include 和 exclude 属性,两者都支持字符串或正则表达式,
    1. include 表示只有名称匹配的组件会被缓存,
    2. exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
    3. 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,
       当组件被移除时,触发钩子函数 deactivated。
    

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

    为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接
    是一个对象?
    
    1.  因为组件是用来复用的,且 JS 里对象是引用关系,如果组件中 data 是一个对象,那么这样
        作用域没有隔离,子组件中的 data 属性值会相互影响
    2.  如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,
        组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在
        引用对象的问题。
    

    14. v-model 的原理?

    我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据
    绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性
    并抛出不同的事件:
    
    1. input 和 textarea 元素使用 value 属性和 input 事件;
    2. checkbox 和 radio 使用 checked 属性和 change 事件;
    3. select 字段将 value 作为 prop 并将 change 作为事件。
    
    以 input 表单元素为例:
    <input v-model='something'>
    相当于
    <input v-bind:value="something" v-on:input="something = $event.target.value">
    

    15. Vue 组件间通信有哪几种方式?

    1.  父子组件通信 [ props / $emit ]
    
    2. 父子组件通信 [ ref 与 $parent / $children ]
       ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,
            引用就指向组件实例
       $parent / $children:访问父 / 子实例
        ref 有三种用法:
            1、ref 加在普通的元素上,用this.ref.name 获取到的是dom元素
            2、ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方法。
            3、如何利用 v-for 和 ref 获取一组数组或者dom 节点
            4、ref 需要在dom渲染完成后才会有,在使用的时候确保dom已经渲染完成。
              比如在生命周期 mounted(){} 钩子中调用,或者在 this.$nextTick(()=>{}) 中调用。
            5、如果ref 是循环出来的,有多个重名,那么ref的值会是一个数组 ,
              此时要拿到单个的ref 只需要循环就可以了。
    
    3. 适用于 父子、隔代、兄弟组件通信  [ EventBus ($emit / $on) ]
       这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,
       从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
    
    4. 适用于 父子、隔代、兄弟组件通信 [ vuex ]
       Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
    

    15-1、 vue中 refs 与 ref
    详情见:https://www.jianshu.com/writer#/notebooks/50167540/notes/84236742/preview

    ref 有三种用法:
      1、ref 加在普通的元素上,用this.ref.name 获取到的是dom元素
      2、ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方法。
      3、如何利用 v-for 和 ref 获取一组数组或者dom 节点
    
    注意:
      1、ref 需要在dom渲染完成后才会有,在使用的时候确保dom已经渲染完成。比如在生命周期 
    mounted(){} 钩子中调用,或者在 this.$nextTick(()=>{}) 中调用。
      2、如果ref 是循环出来的,有多个重名,那么ref的值会是一个数组 ,此时要拿到
    单个的ref 只需要循环就可以了。
    

    16. 使用过 Vue SSR (服务端渲染)吗?说说 SSR?

    1. Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 
    和操作 DOM。然而,也可以将同一个组件渲染为服务端的 HTML 字符串,将它们直接发送到浏览器,最后
    将这些静态标记"激活"为客户端上完全可交互的应用程序。
    即:SSR大致的意思就是vue在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的
    html 片段直接返回给客户端这个过程就叫做服务端渲染。
    
    服务端渲染 SSR 的优缺点如下:
    
    (1)服务端渲染的优点:
    更好的 SEO:因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成
    后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端
    返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;
    
    更快的内容到达时间(首屏加载更快):SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始
    进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端
    渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;
    
    (2) 服务端渲染的缺点:
    更多的开发条件限制:例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些
    外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上
    的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server 运行环境;
    
    更多的服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加
    大量占用CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 
    下使用,请准备相应的服务器负载,并明智地采用缓存策略。
    

    17. vue-router 路由模式有几种?

    vue-router 有 3 种路由模式:hash、history、abstract
    1. Hash:      使用URL的 hash 值来作为路由。支持所有浏览器。
    
    2. History:   以来HTML5 History API 和服务器配置。参考官网中HTML5 History模式
    
    3. Abstract: 支持所有javascript运行模式。如果发现没有浏览器的API,
       路由会自动强制进入这个模式。
    
    vue-router 中默认使用的是 hash 模式,也就是会出现如下的URL:http://localhost:8082/#/home, 
    URL中带有#号
    我们可以用如下代码修改成 history 模式:
    export default new Router({
      mode: 'history',
      routes: [
        {
          path: '/',
          component: Main
        }
      ]
    })
    

    17-01. vue 路由懒加载

    一、为什么要使用路由懒加载
        为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。
    二、定义
      懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。
    三、使用
        常用的懒加载方式有两种:即使用 vue 异步组件 和 ES 中的 import
    
    1、未用懒加载,vue中路由代码如下
     import Vue from 'vue'
     import Router from 'vue-router'
      import HelloWorld from '@/components/HelloWorld'
      Vue.use(Router)
         export default new Router({
              routes: [
                 {
                     path: '/',
                     name: 'HelloWorld',
                     component:HelloWorld
                  }
               ]
      })
    
    2、vue异步组件实现懒加载
        方法如下:component:resolve=>(require(['@/components/backStage/home']),resolve)
    import Vue from 'vue'
    import Router from 'vue-router'
      /* 此处省去之前导入的HelloWorld模块 */
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'HelloWorld',
          component: resolve=>(require(["@/components/HelloWorld"],resolve))
        }
      ]
    })
    
    3、ES 提出的import方法,(------最常用------)
      方法如下:const HelloWorld = ()=>import('需要加载的模块地址')
      不加 { } ,表示直接return)
    import Vue from 'vue'
    import Router from 'vue-router'
    Vue.use(Router)
    
    const HelloWorld = ()=>import("@/components/HelloWorld")
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'HelloWorld',
          component:HelloWorld
        }
      ]
    })
    

    18. Vue 框架怎么实现对象和数组的监听?

    Vue 数据双向绑定主要是指:数据变化更新视图,视图变化更新数据
    即:
    
    输入框内容变化时,Data 中的数据同步变化。即 View => Data 的变化。
    Data 中的数据变化时,文本节点的内容同步变化。即 Data => View 的变化。
    
    其中,View 变化更新 Data ,可以通过事件监听的方式来实现,所以 Vue 的数据双向绑定的工作主要是
    如何根据 Data 变化更新 View。
    
    Vue 主要通过以下 4 个步骤来实现数据双向绑定的:
    1. 实现一个监听器 Observer:
       对数据对象进行遍历,包括子属性对象的属性,利用 
       Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,
       就会触发 setter,那么就能监听到了数据变化。
    
    2. 实现一个解析器 Compile:
       解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染
       页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到
       通知,调用更新函数进行数据更新。
    
    3. 实现一个订阅者 Watcher:
       Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中
       的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
    
    4. 实现一个订阅器 Dep:
       订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 
       Observer 和 订阅者 Watcher 进行统一管理。
    
    image.png
    19. Vue 是如何实现数据双向绑定的?
    如果被问到 Vue 怎么实现数据双向绑定,大家肯定都会回答 通过 Object.defineProperty() 
    对数据进行劫持,但是 Object.defineProperty() 只能对属性进行数据劫持,不能对整个对象进行劫持。
    同理无法对数组进行劫持,但是我们在使用 Vue 框架中都知道,Vue 能检测到对象和数组
    (部分方法的操作)的变化,那它是怎么实现的呢?我们查看相关代码如下:
    /**
       * Observe a list of Array items.
       */
      observeArray (items: Array<any>) {
        for (let i = 0, l = items.length; i < l; i++) {
          observe(items[i])  // observe 功能为监测数据的变化
        }
      }
    
      /**
       * 对属性进行递归遍历
       */
      let childOb = !shallow && observe(val) // observe 功能为监测数据的变化
    
    
    通过以上 Vue 源码部分查看,我们就能知道 Vue 框架是通过遍历数组 和递归遍历对象,从而达到利用 
    Object.defineProperty() 也能对对象和数组(部分方法的操作)进行监听。
    

    22. 虚拟 DOM 的优缺点?

    虚拟 DOM: 
    就是为了解决浏览器性能问题而被设计出来的。如前,若一次操作中有 10 次更新 DOM 的动作,虚拟
    DOM 不会立即操作 DOM ,而是将这 10 次更新的diff内容保存到本地一个JS 对象中,最终将这个 JS
    对象一次性 attch 到 DOM 树上,再进行后续操作,避免大量无谓的计算量。
    所以,用 JS 对象模拟 DOM 节点的好处是,页面的更新可以先全部反映在JS 对象(虚拟 DOM )上,
    操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的 JS 对象映射成真实的 DOM,
    交由浏览器去绘制
    
    优势:
    1. 保证性能下限: 
        框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是
        普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 
        DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
    
    2. 无需手动操作 DOM:
       我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据
       双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
    
    3. 跨平台: 
      虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便
      地跨平台操作,例如服务器渲染、weex 开发等等。
    
    缺点: 
    1. 无法进行极致优化: 
      虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中
      虚拟 DOM  无法进行针对性的极致优化。
      首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,会比 innerHTML插入慢。
     
    

    23. 虚拟 DOM 实现原理?

    虚拟 DOM 的实现原理主要包括以下 3 部分:
    
    1. 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
    2. diff 算法 — 比较两棵虚拟 DOM 树的差异;
    3. pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
    

    24. Vue 中的 key 有什么作用?

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

    25. 你有对 Vue 项目进行哪些优化?

    1)代码层面的优化
    
    v-if 和 v-show 区分使用场景
    computed 和 watch 区分使用场景
    v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
    长列表性能优化
    事件的销毁
    图片资源懒加载
    路由懒加载
    第三方插件的按需引入
    优化无限列表性能
    服务端渲染 SSR or 预渲染
    _____________________________________________________________________
    
    (2)Webpack 层面的优化
    
    Webpack 对图片进行压缩
    减少 ES6 转为 ES5 的冗余代码
    提取公共代码
    模板预编译
    提取组件的 CSS
    优化 SourceMap
    构建结果输出分析
    Vue 项目的编译优化
    
    _____________________________________________________________________
    
    (3)基础的 Web 技术的优化
    
    开启 gzip 压缩
    浏览器缓存
    CDN 的使用
    使用 Chrome Performance 查找性能瓶颈
    
    

    26. 对于 vue3.0 特性你有什么了解的吗?

    Vue 3.0 的目标是让 Vue 核心变得更小、更快、更强大,因此 Vue 3.0 增加以下这些新特性:
    
    (1)监测机制的改变
    3.0 将带来基于代理 Proxy 的 observer 实现,提供全语言覆盖的反应性跟踪。这消除了 Vue 2 当中
    基于 Object.defineProperty 的实现所存在的很多限制:
    
    只能监测属性,不能监测对象
    检测属性的添加和删除;
    检测数组索引和长度的变更;
    支持 Map、Set、WeakMap 和 WeakSet。
    

    27. 修饰符

    1. .lazy
    在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。
    你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步:
    <!-- 在“change”时而非“input”时更新 -->
    <input v-model.lazy="msg" >
    
    2. .number
    如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符
    <input v-model.number="age" type="number">
    
    3. .trim
    如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
    <div id='other'>
            <input v-model.trim='trim'>
            <p ref='tr'>{{trim}}</p>
            <button @click='getStr'>获取</button>
    </div>
    

    28. 事件修饰符

    在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管
    我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
    
    为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
    
    <!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">...</div>
    
    注意:
    
    使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止
    所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
    

    29. 按键修饰符

    常需要检查常见的键值。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
    全部的按键别名:
    .enter
    .tab
    .delete (捕获“删除”和“退格”键)
    .esc
    .space
    .up
    .down
    .left
    .right
    

    30. this.$nextTick()

    当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
    你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。
    
    页面更新完以后再执行方法。
    this.$nextTick() 方法主要是用在随数据改变而改变的 dom 应用场景中,vue 中 数据和
     dom 渲染由于
    是异步的,所以,要让 dom 结构随数据改变这样的操作都应该放进this.$nextTick() 
    的回调
    函数中。created()  中使用的
    方法时,dom 还没有渲染,如果此时在该钩子函数中进行 dom 赋值数据(或者其它 dom 操作)
    时无异于徒劳
    ,所以,此时this.$nextTick() 
    就会被大量使用,而与 created() 对应的是 mounted() 的钩子函数则是在 dom 
    完全渲染后才开始渲染数据,
    所以在 mounted() 中操作 dom 基本不会存在渲染问题。
    

    31. 多个组件有相同逻辑,如何抽离? 用mixin
    mixin 的用法:;定义一个 js文件将export default 中的共有内容写到里面,然后在组件中import,放到 mixin数组中
    mixin缺点就是,不可知,不易维护
    因为你可以在mixins里几乎可以加任何代码,props、data、methods、各种东西,就导致如果不了解mixins封装的代码的话,是很难维护的

    image.png
    image.png

    31. v-on可以监听多个方法吗?

    答:可以,栗子:<input type="text" v-on="{ input:onInput,focus:onFocus,blur:onBlur, }">。
    

    32.请说出vue.cli项目中src目录每个文件夹和文件的用法

    答:assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置; app.vue是一个应用主组件;main.js是入口文件。
    

    33. vue-loader是什么?使用它的用途有哪些?

    答:vue文件的一个加载器,将template/js/style转换成js模块。
    用途:js可以写es6、style样式可以scss或less、template可以加jade等
    

    34.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应该放到外层去。
    

    35.assets和static的区别
    答:相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点
    不相同点:assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。
    建议:将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。
    35.vue和jQuery的区别

    答:jQuery是使用选择器($)
    
    选取DOM对象,对其进行赋值、取值、事件绑定等操作,
    其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:$("lable").val();,它还是依赖DOM元素的值。
    Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。
    

    36.delete和Vue.delete删除数组的区别

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

    37.SPA首屏加载慢如何解决

    答:安装动态懒加载所需插件;使用CDN资源。
    

    38.Vue-router跳转和location.href有什么区别

    答:使用location.href='/url'来跳转,简单方便,但是刷新了页面;
    使用history.pushState('/url'),无刷新页面,静态跳转;
    引进router,然后使用router.push('/url')来跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。
    其实使用router跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下。
    

    39. vue slot

    答:简单来说,假如父组件需要在子组件内放一些DOM,那么这些DOM是显示、不显示、在哪个地方显示、如何显示,就是slot分发负责的活。
    

    40.你们vue项目是打包了一个js文件,一个css文件,还是有多个文件

    答:根据vue-cli脚手架规范,一个js文件,一个CSS文件。
    

    41.Vue里面router-link在电脑上有用,在安卓上没反应怎么解决?

    答:Vue路由在Android机上有问题,babel问题,安装babel polypill插件解决。
    

    42.Vue2中注册在router-link上事件无效解决方法

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

    43.vue-router 是什么?它有哪些组件

    答:vue用来写路由一个插件。router-link、router-view
    

    44.active-class 是哪个组件的属性

    答:active-class是vue-router模块的router-link组件中的属性,用来做选中样式的切换。children数组来定义子路由
    

    45.怎么定义 vue-router 的动态路由? 怎么获取传过来的值

    答:在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id。
    

    46.vue-router 有哪几种路由守卫
    详情:https://blog.csdn.net/LuckXinXin/article/details/108574389
    答:三种,
    第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
    第二种:组件内的守卫

    第三种:单独路由独享组件: 路由配置里

    routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => {
            // ...
          }
        }
    

    47.route 和router 的区别
    详情:https://www.jianshu.com/p/758bde4d9c2e

    答:$router是VueRouter的实例,在script标签中想要导航到不同的URL,使用$router.push方法。返回上一个
    历史history用$router.to(-1)$route为当前router跳转对象。
    $route 可以获取当前路由的name,path,query,parmas等。
    

    相关文章

      网友评论

          本文标题:vue

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