美文网首页Vue
前端知识体系3.Vue

前端知识体系3.Vue

作者: 前端辉羽 | 来源:发表于2020-04-10 09:27 被阅读0次

本文目录

  • 1.简述Vue的响应式原理
  • 2.delete和Vue.delete删除数组的区别
  • 3.v-for循环时为什么要加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.对于仅仅用来展示的长列表数据怎么进行优化

1.简述Vue的响应式原理

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

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

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

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

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

放弃 Object.defineProperty ,使用更快的原生 Proxy (访问对象拦截器, 也成代理器)
提速, 降低内存使用, 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)
}

相关文章

网友评论

    本文标题:前端知识体系3.Vue

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