VUE 常问知识点

  • 1.v-if 和v-show区别

v-if 真正条件渲染 DOM切换 销毁 重建,不停的销毁和创建比较消耗性能。
v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;

  • 2 .created()和mounted()的区别

created()最早使用data中的数据 mounted()最早操作dom节点的函数
接口请求一般放在mounted中,但需要注意的是服务端渲染时不支持mounted,需要放到created中。

  • 3.vue中data为什么必须是一个函数

1.data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了
2.对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。

  • 4.watch、computed和methods的区别

computed 计算属性 计算结果会缓存,只有当依赖值改变才会重新计算
watch 监听属性 一个值的改变 需要另一个值的改变而改变,结果不会缓存
methods 事件方法 调用一次,执行一次,结果不会缓存

  • 5. mvvm的理解

mvvm主要解决mvc中大量使用DOM,使页面渲染性能降低,加载速度变慢,影响使用体验,mvc模式当mode发生变化,开发者需要主动更新view

  • 6.template 只有一个根元素

每一个组件的本质就是Vue实例,既然是Vue的实例就需要一个根入口,如果没有,多个div就无法指定Vue的实例根入口,就像HTML只有一个根元素一样,多个根元素无法构成一棵树,所以template只有一个根元素。

  • 7.vue中怎么重置data

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象
this.$data获取当前状态下的data
this.$options.data()获取该组件初始状态下的data。
Object.assign(this.$data, this.$options.data())

  • 8.Object.defineProperty的理解

Object.defineProperty定义新属性或修改原有的属性;
vue的数据双向绑定的原理就是用的Object.defineProperty这个方法,里面定义了setter和getter方法,通过观察者模式(发布订阅模式)来监听数据的变化,从而做相应的逻辑处理。

  • 9.vue组件会在什么时候下被销毁?

页面关闭、路由跳转、v-if和改变key值

  • 10.vue的is这个特性

vue中is的属性引入是为了解决dom结构中对放入html的元素有限制的问题;
动态组件的例子

<ul><li is='my-component'></li></ul>
  <div id="app">
    <button @click="switchComp('A')">首页 -- 点我显示A 组件 </button>
    <button @click="switchComp('B')">推荐页 -- 点我显示B 组件</button>
    <button @click="switchComp('C')">搜索 -- 点我显示 C 组件</button>
    <button @click="switchComp('D')">点我显示 D组件 </button>
    <component :is="currentComp"></component>  <!--  is  -->
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    Vue.component('componentA', {
      template: '<div>你好呀~ 欢迎来到首页 ~~ </div>'
    });
    Vue.component('componentB',{
      template: '<div>你好呀~  欢迎来到推荐页 ~~ </div>'
    });
    Vue.component('componentC',{
      template: '<div> 你好呀~  欢迎来到搜索页 ~~ </div>'
    })
    let componentD = {
      template: '<div>D</div>'
    }
  let app = new Vue({
    el: '#app',
    components: { componentD },
    data: {
      currentComp: 'componentA'
    },
    methods: {
      switchComp(tag) {
        this.currentComp = 'component' + tag
      }
    } 
  })
  </script>
  • 11.vue的:class和:style有几种表示方式?

:class 1.绑定变量 2.绑定对象 3.绑定一个数组 4.绑定三元表达式
:style 1.绑定变量 2.绑定对象 3.绑定函数返回值 4.绑定三元表达式

  • 12.怎么在watch监听开始之后立即被调用?

watch时有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。

  let vm=new Vue({
        el:"#first",
        data:{msg:'liuneng'},
        watch:{

            msg:{
                handler (newMsg,oldMsg){
                    console.log(newMsg);
                },
                immediate:true  //设置immediate属性为true
            }
        }
    })
  • 13.Vue怎么在路由中配置404页面

在router.js中,由于路由是从上到下执行的,只要在路由配置中最后面放个*号就可以了,例如:
最后一个就是404

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/index'
import na from '@/components/newDetail'
import ga from '@/components/goodlist'
import notfount from '@/components/404'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/newDetail',
      name: 'newDetail',
      component: na
    },
    {
      path: '/goodlist',
      name: 'goodlist',
      component: ga
    },
    {
  path: '*',
    name: 'notfount',
    component: notfount
    }
  ]
})
  • 14.CLI2 Runtime-Compiler和Runtime-only的区别

runtime-compiler(v1)(运行过程)): template -> ast -> render -> vdom -> UI
runtime-only(v2 1.性能更高, 2.代码量更少):render -> vdom -> UI
那.vue文件中的template是由谁处理的呢? 是由vue-template-compiler这个开发时 工具依赖来处理的,他将.vue文件解析成了render函数,解析之后,是没有tamplate这个 东西的
总结:
如果在开发中,依然使用template,就需要选择Runtime-Compiler
如果在开发中,使用的是.vue文件夹开发,那么可以选择Runtime-Only

  • 15.强制更新组件的方法有哪些?分别有何利弊?

简单粗暴的方式:重新加载整个页面
不妥的方式:使用 v-if
较好的方法:使用Vue的内置forceUpdate方法
最好的方法:在组件上进行 key 更改

调用强制更新方法this.$forceUpdate()会更新视图和数据,触发updated生命周期。

<button @click="reload()">强制更新</button>
updated(){
      console.log("更新了");
  },
  methods:{
      reload(){
          this.$forceUpdate();
      }
  }
  • 16.什么是虚拟DOM?

虚拟DOM是:用JS来模拟一颗 DOM 树,放在浏览器内存中
当你要改变时,虚拟 DOM 使用 diff 算法进行 新旧虚拟 dom 的比较将修改了的更新到实际的 DOM 树,减少了 DOM 操作
虚拟 dom 是相对于浏览器所渲染出来的真实 dom 的,在react,vue等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 dom 树的方式找到需要修改的 dom 然后修改样式行为或者结构,来达到更新 ui 的目的。这种方式相当消耗计算资源,因为每次查询 dom 几乎都需要遍历整颗 dom 树,如果建立一个与 dom 树对应的虚拟 dom 对象( js 对象),以对象嵌套的方式来表示 dom 树,那么每次 dom 的更改就变成了 js 对象的属性的更改,这样一来就能查找 js 对象的属性变化要比查询 dom 树的性能开销小。

  • 17.vue组件之间的通信都有哪些?

父子Coms: 1/2/3 ..
兄弟Coms: 4/5
跨级Coms: 4/5/6/7
1.props
2.$emit/$on
3.( $parents/$children ) / $refs
4.Vuex
5.Bus
6.( provide/inject )
7.( $attrs/$listeners )

  • 18.route 和$router的区别

$router是new Router的实例,是全局路由对象,用于进行路由跳转等操作,想要导航到不同 URL,则使用 $router.push 方法;
$route是路由信息对象,表示当前活跃的路由对象,用于读取路由参数;可以从里面获取name,path,params,query等;
简单来说也就是,操作找$router,读参找$route。

  • 19.@click 绑定多个事件?
1,v-on绑定多个方法多个函数?:
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>
一个事件绑定多个函数:
<p @click="one(),two()">点击</p>
  • 20.切换到新路由时,页面要滚动到顶部或保持原先的滚动位置

在路由实例中配置
scrollBehavior(ro,form,savedPosition){
//滚动到顶部
return {x:0,y:0}
//保持原先的滚动位置
return {selector:falsy}
}

  • 21.vue 修饰符sync的功能

vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定,这样就实现了prop的双向绑定。

  • 22.vue complier

compiler模块Vue框架中用于模板编译的,它的作用就是将Vue中的组件模板转换成render函数,render函数在运行时可以生成虚拟节点vnode,它是Vue中虚拟DOM树的基本实现流程。完整版的Vue是包含runtime和compiler的,也就是说模板的编译过程可以在运行时进行,这无疑是一种性能负担。Vue官方也提供了独立的runtime版本,其中只包含运行时环境,把从template到render函数的生成部分放在构建时完成(利用vue-templete-compiler模块),以提高运行时的效率。

  • 23.Vue.use() 作用

提供install 方法,只是为了让 Vue 可以将组件注册到框架里去,使其能够被全局使用。

  • 24.怎么解决vue动态设置img的src不生效的问题?

因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require。
<img :src="require('@/assets/images/xxx.png')" />

  • 25.怎么解决vue打包后静态资源图片失效的问题?

找到config/index.js 配置文件,找build打包对象里的assetsPublicPath属性
默认值为/,更改为./就好了
最新的vue-cli 需要在根目录下建一个vue.config.js 在里面配置publicPath即可

  • 26.vue渲染模板时怎么保留模板中的HTML注释呢?

设置comments属性,官网默认为舍弃注释
<template comments> ... </template>

  • 27.vue中使用插件的步骤?

安装:npm install xxx
引入: import ... from ...;
使用:Vue.use(xxx)

  • 28.vue中引入组件有几种方式?

两种:采用 ES6 的 import ... from ... 语法或 CommonJS 的 require() 方法引入组件

//方法一
import Calendar from "./calendar";
export default {
  name: "SymptomMain",
  components: {
    Calendar
  },
}
//方法二
export default {
//1.直接在components中写入子组件
components: {
    Calendar:require('./calendar.vue').default
  },
}
  • 29.vue-router 有哪几种导航钩子

1.全局导航钩子 作用:跳转前进行判断拦截。
router.beforeEach(to,from,next);
router.beforeResolve(to,from,next);
router.afterEach(to,from,next);

2.组件内钩子
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

3.单独路由独享组件
beforeEnter

  • 30.v-model的原理

原生input其实只是一个语法糖
:bind="value"与@change="value = $event.target.value"的结合。

  • 31.父组件怎么接收子组件的多个参数

this.$emit("eventName",data)
data为一个对象
data 对象或数组都可以的。

  • 32.怎么解决vue动态设置img的src不生效的问题?

因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require。

<img :src="require('../../../assets/images/xxx.png')" />
  • 33.keep-alive有关的生命周期是哪些?描述下这些生命周期

activated和deactivated
keep-alive的生命周期
1.activated: 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
2.deactivated: 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated

  • 34.vue中怎么重置data?

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。

this.$data获取当前状态下的data
this.$options.data()获取该组件初始状态下的data。
Object.assign(this.$data, this.$options.data())

  • 35.在vue事件中传入$event,使用e.target和e.currentTarget有什么区别?

currentTarget:事件绑定的元素
target:鼠标触发的元素
event.currentTarget指向事件所绑定的元素,而event.target始终指向事件发生时的元素。

  • 36.vue如果想扩展某个现有的组件时,怎么做呢?

1.使用Vue.extend直接扩展
2.使用Vue.mixin全局混入
3.HOC封装
4.slot扩展

  • 36.v-once的使用场景

v-once这个指令不需要任何表达式,它的作用就是定义它的元素或组件只会渲染一次,包括元素或者组件的所有字节点。首次渲染后,不再随着数据的改变而重新渲染。也就是说使用v-once,那么该块都将被视为静态内容。<div v-once>{{count}}</div>

  • 37.表单修饰符和事件修饰符

事件修饰符.stop .prevent .capture .self .once .passive
表单修饰符.number .lazy .trim

  • 38.v-clock和v-pre指令

v-cloak指令只是在标签中加入一个v-cloak自定义属性,在HTML还编译完成之后该属性会被删除。
v-pre可以用来阻止预编译,有v-pre指令的标签内部的内容不会被编译,会原样输出。

  • 39.proxy的理解

vue的数据劫持有两个缺点:

1、无法监听通过索引修改数组的值的变化
2、无法监听object也就是对象的值的变化

所以vue2.x中才会有$set属性的存在
proxy是es6中推出的新api,可以弥补以上两个缺点,所以vue3.x版本用proxy替换object.defineproperty

  • 40. Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?

判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。

  • 41. 监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?

我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。

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

可以通过@hook来监听生命周期事件,用法如下:

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
   console.log('父组件监听到 mounted 钩子函数 ...');
},
    
//  Child.vue
mounted(){
   console.log('子组件触发 mounted 钩子函数 ...');
},    
    
// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ... 
  • 43.Vue实现数据双向绑定的原理:Object.defineProperty()

1.vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
2.vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
3.通过Observer 把数据劫持(Object.defineProperty()) 、加入到订阅器(Dep) 订阅器收集订阅者(Watcher )、视图通过编译(Compile)、解析指令(Directive)等一些列操作收集给订阅者 、最后通过触发数据变化update 通知所有订阅者完成数据驱动

  • 44.服务端渲染(SSR)和预渲染(Prerendering)有什么区别?

1.服务端渲染的过程为:解析执行JS => 构建HTML页面 => 输出给浏览器
2.预渲染:直接输出HTML页面给浏览器

  • 45.vue从data改变到页面渲染的过程

(1)把模板编译为render函数
(2)实例进行挂载,根据节点render函数的调用,递归的生成虚拟dom;
(3)对比虚拟dom,渲染真实dom;
(4)组件内部data发生变化,组件和子组件引用data作为props重新调用render函数生成虚拟dom返回 对比虚拟dom,渲染真实dom的操作;

  • 46 介绍一下Vue的响应式系统

Vue为MVVM框架,当数据模型data变化时,页面视图会得到响应更新,其原理对data的getter/setter方法进行拦截(Object.defineProperty或者Proxy),利用发布订阅的设计模式,在getter方法中进行订阅,在setter方法中发布通知,让所有订阅者完成响应。
在响应式系统中,Vue会为数据模型data的每一个属性新建一个订阅中心作为发布者,而监听器watch、计算属性computed、视图渲染template/render三个角色同时作为订阅者,对于监听器watch,会直接订阅观察监听的属性,对于计算属性computed和视图渲染template/render,如果内部执行获取了data的某个属性,就会执行该属性的getter方法,然后自动完成对该属性的订阅,当属性被修改时,就会执行该属性的setter方法,从而完成该属性的发布通知,通知所有订阅者进行更新。

  • 47computed与watch的区别

计算属性computed和监听器watch都可以观察属性的变化从而做出响应,不同的是:

计算属性computed更多是作为缓存功能的观察者,它可以将一个或者多个data的属性进行复杂的计算生成一个新的值,提供给渲染函数使用,当依赖的属性变化时,computed不会立即重新计算生成新的值,而是先标记为脏数据,当下次computed被获取时候,才会进行重新计算并返回。

而监听器watch并不具备缓存性,监听器watch提供一个监听函数,当监听的属性发生变化时,会立即执行该函数。

  • 48介绍一下Vue的生命周期

beforeCreate:是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。

created:在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。

beforeMount:发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。

mounted:在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。

beforeUpdate:发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。

updated:发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。

beforeDestroy:发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。

destroyed:发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

  • 49为什么组件的data必须是一个函数

一个组件可能在很多地方使用,也就是会创建很多个实例,如果data是一个对象的话,对象是引用类型,一个实例修改了data会影响到其他实例,所以data必须使用函数,为每一个实例创建一个属于自己的data,使其同一个组件的不同实例互不影响。

  • 50组件之间是怎么通信的

父子组件通信
父组件 -> 子组件:prop

子组件 -> 父组件:on/emit

获取组件实例:使用parent/children,$refs.xxx,获取到实例后直接获取属性数据或调用组件方法

兄弟组件通信
Event Bus:每一个Vue实例都是一个Event Bus,都支持on/emit,可以为兄弟组件的实例之间new一个Vue实例,作为Event Bus进行通信。

Vuex:将状态和方法提取到Vuex,完成共享

跨级组件通信
使用provide/inject

Event Bus:同兄弟组件Event Bus通信

Vuex:将状态和方法提取到Vuex,完成共享

  • 51 Vue事件绑定原理说一下

每一个Vue实例都是一个Event Bus,当子组件被创建的时候,父组件将事件传递给子组件,子组件初始化的时候是有$on方法将事件注册到内部,在需要的时候使用$emit触发函数,而对于原生native事件,使用addEventListener绑定到真实的DOM元素上。

  • 52 slot是什么?有什么作用?原理是什么?

slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。

slot又分三类,默认插槽,具名插槽和作用域插槽。

默认插槽:又名匿名查抄,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。
具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。
作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。
实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

  • 53 Vue模板渲染的原理是什么?

vue中的模板template无法被浏览器解析并渲染,因为这不属于浏览器的标准,不是正确的HTML语法,所有需要将template转化成一个JavaScript函数,这样浏览器就可以执行这一个函数并渲染出对应的HTML元素,就可以让视图跑起来了,这一个转化的过程,就成为模板编译。

模板编译又分三个阶段,解析parse,优化optimize,生成generate,最终生成可执行函数render。

parse阶段:使用大量的正则表达式对template字符串进行解析,将标签、指令、属性等转化为抽象语法树AST。
optimize阶段:遍历AST,找到其中的一些静态节点并进行标记,方便在页面重渲染的时候进行diff比较时,直接跳过这一些静态节点,优化runtime的性能。
generate阶段:将最终的AST转化为render函数字符串。

  • 54 template预编译是什么?

对于 Vue 组件来说,模板编译只会在组件实例化的时候编译一次,生成渲染函数之后在也不会进行编译。因此,编译对组件的 runtime 是一种性能损耗。

而模板编译的目的仅仅是将template转化为render function,这个过程,正好可以在项目构建的过程中完成,这样可以让实际组件在 runtime 时直接跳过模板渲染,进而提升性能,这个在项目构建的编译template的过程,就是预编译。

  • 55 template和jsx的有什么分别?

对于 runtime 来说,只需要保证组件存在 render 函数即可,而我们有了预编译之后,我们只需要保证构建过程中生成 render 函数就可以。

在 webpack 中,我们使用vue-loader编译.vue文件,内部依赖的vue-template-compiler模块,在 webpack 构建过程中,将template预编译成 render 函数。

与 react 类似,在添加了jsx的语法糖解析器babel-plugin-transform-vue-jsx之后,就可以直接手写render函数。

所以,template和jsx的都是render的一种表现形式,不同的是:

JSX相对于template而言,具有更高的灵活性,在复杂的组件中,更具有优势,而 template 虽然显得有些呆滞。但是 template 在代码结构上更符合视图与逻辑分离的习惯,更简单、更直观、更好维护。

  • 56 说一下什么是Virtual DOM

Virtual DOM 是 DOM 节点在 JavaScript 中的一种抽象数据结构,之所以需要虚拟DOM,是因为浏览器中操作DOM的代价比较昂贵,频繁操作DOM会产生性能问题。虚拟DOM的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue对比更新前后的虚拟DOM,匹配找出尽可能少的需要更新的真实DOM,从而达到提升性能的目的。

  • 57 介绍一下Vue中的Diff算法

在新老虚拟DOM对比时

首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换
如果为相同节点,进行patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)
比较如果都有子节点,则进行updateChildren,判断如何对这些新老节点的子节点进行操作(diff核心)。
匹配时,找到相同的子节点,递归比较子节点
在diff中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从O(n^3)降低值O(n),也就是说,只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较。

  • 58 key属性的作用是什么

key值得作用:增加唯一性,更高效的更新虚拟DOM,便于diff算法的更新,key值得唯一性更快的更新虚拟DOM。

diff算法对DOM进行原地复用,减少DOM性能耗费。

  • 59 说说Vue2.0和Vue3.0有什么区别

重构响应式系统,使用Proxy替换Object.defineProperty,使用Proxy优势:

可直接监听数组类型的数据变化
监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升
可拦截apply、ownKeys、has等13种方法,而Object.defineProperty不行
直接实现对象属性的新增/删除
新增Composition API,更好的逻辑复用和代码组织

重构 Virtual DOM

模板编译时的优化,将一些静态节点编译成常量
slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件
模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数)
代码结构调整,更便于Tree shaking,使得体积更小

使用Typescript替换Flow

  • 60 为什么要新增Composition API,它能解决什么问题

Vue2.0中,随着功能的增加,组件变得越来越复杂,越来越难维护,而难以维护的根本原因是Vue的API设计迫使开发者使用watch,computed,methods选项组织代码,而不是实际的业务逻辑。

另外Vue2.0缺少一种较为简洁的低成本的机制来完成逻辑复用,虽然可以minxis完成逻辑复用,但是当mixin变多的时候,会使得难以找到对应的data、computed或者method来源于哪个mixin,使得类型推断难以进行。

所以Composition API的出现,主要是也是为了解决Option API带来的问题,第一个是代码组织问题,Compostion API可以让开发者根据业务逻辑组织自己的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他自己写的代码时,他可以更好的利用代码的组织反推出实际的业务逻辑,或者根据业务逻辑更好的理解代码。

第二个是实现代码的逻辑提取与复用,当然mixin也可以实现逻辑提取与复用,但是像前面所说的,多个mixin作用在同一个组件时,很难看出property是来源于哪个mixin,来源不清楚,另外,多个mixin的property存在变量命名冲突的风险。而Composition API刚好解决了这两个问题。

  • 61 都说Composition API与React Hook很像,说说区别

从React Hook的实现角度看,React Hook是根据useState调用的顺序来确定下一次重渲染时的state是来源于哪个useState,所以出现了以下限制

不能在循环、条件、嵌套函数中调用Hook
必须确保总是在你的React函数的顶层调用Hook
useEffect、useMemo等函数必须手动确定依赖关系
而Composition API是基于Vue的响应式系统实现的,与React Hook的相比

声明在setup函数内,一次组件实例化只调用一次setup,而React Hook每次重渲染都需要调用Hook,使得React的GC比Vue更有压力,性能也相对于Vue来说也较慢
Compositon API的调用不需要顾虑调用顺序,也可以在循环、条件、嵌套函数中使用
响应式系统自动实现了依赖收集,进而组件的部分的性能优化由Vue内部自己完成,而React Hook需要手动传入依赖,而且必须必须保证依赖的顺序,让useEffect、useMemo等函数正确的捕获依赖变量,否则会由于依赖不正确使得组件性能下降。
虽然Compositon API看起来比React Hook好用,但是其设计思想也是借鉴React Hook的。

  • 62 SSR有了解吗?原理是什么?

在客户端请求服务器的时候,服务器到数据库中获取到相关的数据,并且在服务器内部将Vue组件渲染成HTML,并且将数据、HTML一并返回给客户端,这个在服务器将数据和组件转化为HTML的过程,叫做服务端渲染SSR。

而当客户端拿到服务器渲染的HTML和数据之后,由于数据已经有了,客户端不需要再一次请求数据,而只需要将数据同步到组件或者Vuex内部即可。除了数据意外,HTML也结构已经有了,客户端在渲染组件的时候,也只需要将HTML的DOM节点映射到Virtual DOM即可,不需要重新创建DOM节点,这个将数据和HTML同步的过程,又叫做客户端激活。

  • 63 使用SSR的好处:

有利于SEO:其实就是有利于爬虫来爬你的页面,因为部分页面爬虫是不支持执行JavaScript的,这种不支持执行JavaScript的爬虫抓取到的非SSR的页面会是一个空的HTML页面,而有了SSR以后,这些爬虫就可以获取到完整的HTML结构的数据,进而收录到搜索引擎中。
白屏时间更短:相对于客户端渲染,服务端渲染在浏览器请求URL之后已经得到了一个带有数据的HTML文本,浏览器只需要解析HTML,直接构建DOM树就可以。而客户端渲染,需要先得到一个空的HTML页面,这个时候页面已经进入白屏,之后还需要经过加载并执行 JavaScript、请求后端服务器获取数据、JavaScript 渲染页面几个过程才可以看到最后的页面。特别是在复杂应用中,由于需要加载 JavaScript 脚本,越是复杂的应用,需要加载的 JavaScript 脚本就越多、越大,这会导致应用的首屏加载时间非常长,进而降低了体验感。

  • 64 vue 数组使用push pop 等为什么是响应式的?

把数组原有的方法, 继续执行, 后面增加了ob.dep.notify() ,这个里面放着订阅者模式里面的订阅者,通过notify来通知订阅者做处理

  • 65 render和template 的关系

1.性质相同 都是类编译器. 2. template=>render(创建)=》虚拟DOM(js对象)=》真实DOM. 3.互补的关系

  • 66 vuex为什么不建议在action中修改state

action的回调会被当作普通函数执行,而当如果有多个声明时,它们是被视为Promise实例,并且用Promise.all执行,总所周知,Promise.all在执行Promise时是不保证顺序的,也就是说,假如有3个Promise实例:P1、P2、P3,它们3个之中不一定哪个先有返回结果,那么我们仔细思考一下:如果同时在多个action中修改了同一个state,那会有什么样的结果?

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