前端知识体系3.Vue

本文目录

  • 1.简述Vue的响应式原理
  • 2.delete和Vue.delete删除数组的区别
  • 3.v-for循环时为什么要加key,为什么不推荐用index作为key
  • 4.Vue 组件 data 为什么必须是函数
  • 5.Vue 的核心是什么
  • 6.Vue 等SPA单页面应用的优缺点
  • 7.v-if 和 v-show 有什么区别?
  • 8.Vue中如何监控某个属性值的变化?
  • 9.Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?
  • 10.$route$router 的区别
  • 11.computed 和 watch 的区别和运用的场景
  • 12.路由模式hash和history的区别
  • 13.对MVC和MVVM的理解
  • 14.vue如何实现数据双向绑定
  • 15.简述vue的原理
    1. 简要说一下vue的生命周期
  • 17.vue的diff算法原理
  • 18.二次封装axios的基本思路
    1. vue首屏优化加载时间的方法
  • 20.当单页面应用的体量越来越大时,只有一个页面会难以应对负责的业务场景,此时可以进行两个方面的优化:1.将单页面应用拆分成多个页面。 2.将几十甚至上百个路由进行重新规划。讲一下你对这两方面的见解。
  • 21.说一下vue3版本的新特性
  • 22.actions 和 mutations 有什么区别。
  • 23.怎么实现axios的同步请求
  • 24.说下常用的组件通信方法
  • 25.vue怎么进行seo优化
  • 26.data中某个数据想解除双向绑定该怎么做
  • 27.页面中定义一个定时器,在哪个阶段清除
  • 28.vue中data的属性可以和methods中的方法同名吗
  • 29.怎么缓存当前的组件?缓存后怎么更新
  • 30.怎么实现路由懒加载
  • 31.vuex有哪几种属性
  • 32.对于仅仅用来展示的长列表数据怎么进行优化
  • 33.像vue-router,vuex这些vue插件是如何在vue中生效的
  • 34.Vue.nextTick()的使用情景
  • 35.mounted之后就一定能getElementById获取到DOM节点吗
  • 36.Vue模板渲染的原理是什么
  • 37.template预编译是什么
  • 38.template和jsx的有什么分别
  • 39.说说Vue2.0和Vue3.0有什么区别
  • 40.为什么要新增Composition API,它能解决什么问题
  • 41.都说Composition API与React Hook很像,说说区别
  • 42.什么是虚拟DOM
  • 43.keep-alive的实现原理
  • 44.v-model的实现原理
  • 45.如何实现监听路由

1.简述Vue的响应式原理

当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。

Vue的双向数据绑定是通过数据劫持结合发布者订阅者模式来实现的 要实现这种双向数据绑定,必要的条件有:

1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者 2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数 3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图 4、MVVM入口函数,整合以上三者

个人理解:
在new Vue的时候,在Observer中通过Object.defineProperty()达到数据劫持,代理所有数据的getter和setter属性,在每次触发setter的时候,都会通过Dep来通知Watcher,Watcher作为Observer数据监听器与Compile模板解析器之间的桥梁,当Observer监听到数据发生改变的时候,通过Updater来通知Compile更新视图** **而Compile通过Watcher订阅对应数据,绑定更新函数,通过Dep来添加订阅者,达到双向绑定。

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

delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。

var a = [1,2,3,4]
delete a[1]
console.log(a)
//[1, empty, 3, 4]
console.log(a[1])
//undefined

Vue.delete 直接删除了数组对应的项,改变了数组的键值。

var c=[1,2,3,4]
this.$delete(c,1)
console.log(c)
//[1,3,4]

3.v-for循环时为什么要加key,为什么不推荐用index作为key

key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
总结:当v-for循环出的元素需要进行到动态的变化的时候,是一定要绑定key值的。

用 index 作为 key 时,在对数据进行,逆序添加,逆序删除等破坏顺序的操作时,会产生没必要的真实 DOM更新,从而导致效率低
用 index 作为 key 时,如果结构中包含输入类的 DOM,会产生错误的 DOM 更新
在开发中最好每条数据使用唯一标识固定的数据作为 key,比如后台返回的 ID,手机号,身份证号等唯一值
如果不存在对数据逆序添加,逆序删除等破坏顺序的操作时,仅用于渲染展示用时,使用 index 作为 key 也是可以的(但是还是不建议使用,养成良好开发习惯)。

4.Vue 组件 data 为什么必须是函数

因为 JS 本身的特性带来的,如果 data 是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性时,会影响到所有 Vue 实例的数据。如果将 data 作为一个函数返回一个对象,那么每一个实例的 data 属性都是独立的,不会相互影响了。

5.Vue 的核心是什么

数据驱动、组件系统。
jQuery 专注视图层,通过操作 DOM 去实现页面的一些逻辑渲染; Vue 专注于数据层,通过数据的双向绑定,最终表现在 DOM 层面,减少了 DOM 操作。

6.Vue 等SPA单页面应用的优缺点

优点

  • 良好的交互体验
  • 良好的前后端工作分离模式
  • 减轻服务器压力

缺点

  • SEO 难度较高
  • 前进、后退管理逻辑不是那么清晰
  • 初次加载耗时多

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

v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

8.Vue中如何监控某个属性值的变化?

watch: {
    obj: {
        handler (newValue, oldValue) {
            console.log('obj changed')
        },
    deep: true
    }
}

deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:

watch: {
    'obj.a': {
        handler (newValue, oldValue) {
            console.log('obj changed')
        }
    }
}

还有一种方法,可以通过computed 来实现,只需要:

computed : {
    a1 () {
        return this.obj.a
    }
}

利用计算属性的特性来实现,当依赖改变时,便会重新计算一个新值。

9.Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?

给data中的对象增加属性需要用到Vue的全局api—— $set():

this.$set(this.obj, 'b', 'obj.b')

这样$set() 方法相当于手动的去把新增加的属性处理成一个响应式的属性,从而自动触发视图改变。利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue,Vue也是不能检测到的,

10.$route$router 的区别

$router 为 VueRouter 实例,想要导航到不同URL,则使用 $router.push 方法。
$route 为当前 router 跳转对象,里面可以获取 name 、 path 、 query 、 params 等。

11.computed 和 watch 的区别和运用的场景

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:

  • 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
  • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

12.路由模式hash和history的区别

对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义。前端路由的核心,就在于 => 改变视图的同时不会向后端发出请求。
为了达到这一目的,浏览器当前提供了以下两种支持:
1.hash —— 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。
比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
2.history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)
这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
因此可以说,hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
hash
hash路由模式是这样的:http://xxx.abc.com/#/xx。 有带#号,后面就是hash值的变化。改变后面的hash值,它不会向服务器发出请求,因此也就不会刷新页面。hash的url中会夹杂#,会让请求变得不是那么优雅。
history
浏览器地址没有#, 比如(http://localhost:3001/a); 它也一样不会刷新页面的。但是url地址会改变。history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。
对于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 开发场景,用 history 模式比较多,只需在后端(Apache 或 Nginx)进行简单的路由配置,同时搭配前端路由的 404 页面支持。

13.对MVC和MVVM的理解

MVC模式是MVVM模式的基础,MVVM模式更像是MVC模式的优化改良版,他们两个的MV即Model(模型),view(视图)相同,不同的是MV之间的纽带部分。本文主要介绍MVC与MVVM的应用与区别。
MVC
MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
如果前端没有框架,只使用原生的html+js,MVC模式可以这样理解。将html看成view;js看成controller,负责处理用户与应用的交互,响应对view的操作(对事件的监听),调用Model对数据进行操作,完成model与view的同步(根据model的改变,通过选择器对view进行操作);将js的ajax当做Model,也就是数据层,通过ajax从服务器获取数据。
但是现实开发肯定没有刚才的举例那么简单,但是大体原理是这样的。
MVVM
MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。
那MVVM模式的代表Vue举例看,Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定,即Model变化时VIew可以实时更新,View变化也能让Model发生变化。
整体看来,MVVM比MVC精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也观察不到View,这种低耦合模式提高代码的可重用性。
总结
在学习MVC与MVVM架构模式的过程中,经常会对分层的界限叫不准。比如说不清楚js里到底哪里算Model,哪里算Controller,Vue实例里面Model与ViewModel的严格界限在哪,有时候越想越感觉叫不准。当我从头到尾整理完这两种模式特点的时候,发现这个界限没有那么重要。我觉得重要的是,理解两种模式的基本思想,根据应用需求,选择适合自己业务的框架。

14.vue如何实现数据双向绑定

vue的双向绑定是通过数据劫持和发布者-订阅者模式实现的,数据劫持又是通过Object.defineProperty()实现的
mvvm的数据变化更新视图,是通过Object.defineProperty()实现的;视图更新变化数据,是通过事件监听实现的。
发布者-订阅者的实现过程:

  1. 实现一个监听器Observer,劫持并监听所有属性,如果有变化,就通知订阅者
  2. 实现一个订阅者Watcher,收到属性的变化通知并执行响应的函数,从而更新视图
  3. 实现一个解析器Compiler,可以扫描并解析每个节点的相关指令,初始化模板数据和对应的订阅器

15.简述vue的原理

1、建立虚拟DOM Tree,通过document.createDocumentFragment(),遍历指定根节点内部节点,根据{{ prop }}、v-model等规则进行compile;
2、通过Object.defineProperty()进行数据变化拦截;
3、截取到的数据变化,通过发布者-订阅者模式,触发Watcher,从而改变虚拟DOM中的具体数据;
4、通过改变虚拟DOM元素值,从而改变最后渲染dom树的值,通过Object.defineProperty()完成数据的双向绑定。

16. 简要说一下vue的生命周期

答案见《Vue》文集的《组件的生命周期钩子和路由钩子总结》

17.vue的diff算法原理

Diff算法的作用是用来计算出 Virtual DOM(虚拟DOM) 中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。
虚拟dom是对真实dom的一种映射,新旧Vnode比较同层级的节点,然后根据两者的差异只更新有差异的部分,生成新的视图,而不是对树进行逐层搜素遍历,因此时间复杂度是O(n)。虚拟dom可以减少页面的回流和重绘,提升性能。

18.二次封装axios的基本思路

1.新建一个axios对象,定义好字段并设置默认值,比如超时时间、请求头
2.定义过滤字符串方法,过滤服务端为空字符串或null的属性
3.请求拦截器调用过滤字符串方法,遍历url上的字段,如果为数组或对象转为JSON对象
4.响应拦截器捕获错误,根据http状态码进行不同的处理,比如401跳转登陆页面,403返回您没有权限,502返回系统正在升级中,请稍后重试,
504返回系统超时,并弹出对应的消息提示框。消息提示框自定义

19.vue首屏优化加载时间的方法

  • 将公用的JS库通过script标签外部引入,减小 app.bundel 的大小,让浏览器并行下载资源文件,提高下载速度;
  • 在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;
  • 加一个首屏loading图,提升用户体验;

20.当单页面应用的体量越来越大时,只有一个页面会难以应对负责的业务场景,此时可以进行两个方面的优化:1.将单页面应用拆分成多个页面。 2.将几十甚至上百个路由进行重新规划。讲一下你对这两方面的见解。

21.说一下vue3版本的新特性

vue2采用的是defineProperty去定义get,set,而vue3使用更快的原生 Proxy (访问对象拦截器, 也成代理器),这样意味着vue放弃兼容老版本的ie浏览器
提速, 降低内存使用, Tree-shaking更友好
支持IE11等
使用Typescript

22.actions 和 mutations 有什么区别。

23.怎么实现axios的同步请求

24.说下常用的组件通信方法

详细内容见文件《Vue》=>《组件数据通信方案总结》

25.vue怎么进行seo优化

seo关系到网站排名, vue搭建spa做前后端分离不好做seo, 可通过其他方法解决:
SSR服务端渲染: 将同一个组件渲染为服务器端的 HTML 字符串.利于seo且更快.
vue-meta-info, nuxt, prerender-spa-plugin页面预渲染等

26.data中某个数据想解除双向绑定该怎么做

let obj = JSON.parse(JSON.stringify(this.temp1));

27.页面中定义一个定时器,在哪个阶段清除

首先确定的一点肯定是在 beforeDestroy 中销毁定时器。比如在页面 a 中写了一个定时器,比如每隔一秒钟打印一次 1,当我点击按钮进入页面 b 的时候,会发现定时器依然在执行,这是非常消耗性能的。
代码如下:

mounted(){
 this.timer = setInterval(()=>{
    console.log(1)
 },1000)
},
beforeDestroy(){
 clearInterval(this.timer)
}

上面这样的确可以实现功能,但是存在两个缺点:
它需要在这个组件实例中保存这个 timer,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。
我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化的清理我们建立的所有东西。
可以通过$once 这个事件侦听器在定义完定时器之后的位置来清除定时器

mounted(){
 const timer = setInterval(()=>{
    console.log(1)
 },1000)
 this.$once('hook:beforeDestroy',()=>{
  clearInterval(timer)
 })
}

28.vue中data的属性可以和methods中的方法同名吗

不可以,因为Vue会把methods和data的东西,全部代理到Vue生成的对象中,会产生覆盖所以最好不要同名,所以这个问题就和对象中的属性和方法可以重名吗是一个性质。

29.怎么缓存当前的组件?缓存后怎么更新

<keep-alive>
    <router-view></router-view>
</keep-alive>
<!-- 这里是需要keepalive的 -->
<keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 这里不会被keepalive -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
{
  path: '',
  name: '',
  component: ,
  meta: {keepAlive: true} // 这个是需要keepalive的
},
{
  path: '',
  name: '',
  component: ,
  meta: {keepAlive: false} // 这是不会被keepalive的
}

如果缓存的组件想要清空数据或者执行初始化方法,在加载组件的时候调用activated钩子函数,如下:

activated: function () {
    this.data = '';
}

30.怎么实现路由懒加载

第一种(常用):

const Foo = () => import('./Foo.vue')
const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})

第二种(常用):

const router = new Router({
  routes: [
   {
     path: '/index',
     component: (resolve) => {
        require(['../components/index'], resolve) // 这里是你的模块 不用import去引入了
     }
    //或者直接这样写
    //component: () =>
      //import('../components/index')
    }
  ]
})

第三种(官方推荐):
利用webpack提供的require.ensure(),vue-router配置路由时,使用webpack的require.ensure技术,可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
···
// r就是resolve
const list = r => require.ensure([], () => r(require('../components/list/list')), 'list');
// 路由也是正常的写法 这种是官方推荐的写的 按模块划分懒加载
const router = new Router({
routes: [
{
path: '/list/blog',
component: list,
name: 'blog'
}
]
})
···

31.vuex有哪几种属性

有五种,分别是 State、 Getter、Mutation 、Action、 Module
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex

32.对于仅仅用来展示的长列表数据怎么进行优化

Vue 会通过 Object.defineProperty/Proxy 对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 Vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,那如何禁止 Vue 劫持我们的数据呢?可以通过 Object.freeze 方法来冻结一个对象,一旦被冻结的对象就再也不能被修改了。

async getUsers(){
  const users = await axios.get(/api/users)
  this.users =Object.freeze(users)
}

33.像vue-router,vuex这些vue插件是如何在vue中生效的

通过vue的插件系统,用vue.mixin混入到全局,在每个组件的生命周期的某个阶段注入组件实例。

34.Vue.nextTick()的使用情景

官方定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
获取更新后的DOM言外之意就是什么操作需要用到了更新后的DOM而不能使用之前的DOM或者使用更新前的DOM会出问题,所以就衍生出了这个获取更新后的 DOM的Vue方法。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的 js代码。

什么时候需要用Vue.nextTick():
$nextTick的实现原理依赖于js的eventloop事件循环机制,在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

  • 你在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。原因是什么呢,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
  • 在数据变化后要执行的某个操作,当你设置 this.someData = 'new value',DOM并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
  • mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 this.$nextTick 替换掉 mounted:
mounted: function () {
this.$nextTick(function () {

// Code that will run only after the
// entire view has been rendered
})
}

35.mounted之后就一定能getElementById获取到DOM节点吗

是的,前提是该节点并没有被别的条件限制导致无法渲染。

<div v-if="ifCreate === true">
      <div class="demo"></div>
</div>

上面这种情况,如果ifCreate一直都是false,那么无论任何阶段,都找不到demo这个元素。

36.Vue模板渲染的原理是什么

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

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

37.template预编译是什么

对于 Vue 组件来说,模板编译只会在组件实例化的时候编译一次,生成渲染函数之后在也不会进行编译。因此,编译对组件的 runtime 是一种性能损耗。
而模板编译的目的仅仅是将template转化为render function,这个过程,正好可以在项目构建的过程中完成,这样可以让实际组件在 runtime 时直接跳过模板渲染,进而提升性能,这个在项目构建的编译template的过程,就是预编译。

38.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 在代码结构上更符合视图与逻辑分离的习惯,更简单、更直观、更好维护。

39.说说Vue2.0和Vue3.0有什么区别

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

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

2.新增Composition API,更好的逻辑复用和代码组织
3.重构 Virtual DOM

  • 模板编译时的优化,将一些静态节点编译成常量
  • slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件
  • 模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数)

4.代码结构调整,更便于Tree shaking,使得体积更小
5.使用Typescript替换Flow

40.为什么要新增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刚好解决了这两个问题。

41.都说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的。

42.什么是虚拟DOM

虚拟DOM就是将DOM树转换成的一个JS对象树,diff算法逐层比较,删除,添加操作,但是,如果有多个相同的元素,可能会浪费性能,所以,react和vue-for引入key值进行区分。
优点:保证性能下限,无需手动操作 DOM,跨平台
缺点:首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢,无法进行极致优化。

43.keep-alive的实现原理

Vue是通过vnode实现保存节点的,而keep-alive本身也是通过保存vnode来实现缓存的,而不是直接存储DOM结构。其实就是将需要缓存的VNode节点保存在this.cache中/在render时,如果VNode的name符合在缓存条件(可以用include以及exclude控制),则会从this.cache中取出之前缓存的VNode实例进行渲染。

44.v-model的实现原理

v-model其实就是个语法糖

<input v-mdel = "val">
<input :value= "val" @input="val = $event.target.value">

45.如何实现监听路由

Vue中:
1.全局路由守卫

router.beforeEach((to, from, next) => {}

2.页面路由监听

watch:{
    $route:{
      handler(newval,oldval){
        console.log(newval);//新路由信息
        console.log(oldval);//老路由信息
      },
      // 深度观察监听
      deep: true
    }
}

React中:

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

推荐阅读更多精彩内容