【vue面试题】

谈谈你怼MVVM开发模式的理解

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

vue优点

  • 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb ;
  • 简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
  • 双向数据绑定:保留了 angular 的特点,在数据操作方面更为简单;
  • 组件化:保留了 react 的优点,实现了 html 的封装和重用,在构建单页面应用方面有着独特的优势;
  • 视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
  • 虚拟DOM:dom 操作是非常耗费性能的, 不再使用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种方式;
  • 运行速度更快:相比较于 react 而言,同样是操作虚拟 dom ,就性能而言, vue 存在很大的优势。
渐进式框架的理解

主张最少;可以根据不同的需求选择不同的层级;

vue常用的指令

  • v-text:元素的InnerText属性,用于数据绑定
  • v-html:元素的InnerHTML属性,用于绑定一段html
  • v-bind:给元素的属性赋值,v-bind后面是 [:属性名=] [变量名],简写为:属性名
  • v-for:列表的循环渲染。语法v-for="item in data",data 可以是数组或者对象
  • v-show、v-if:控制页面元素的显示和隐藏
  • v-if、v-else-if、v-else:v-if的条件渲染和JavaScript条件判断语句中if、else、else if非常类似。
  • v-on:给元素绑定事件,用法v-on:事件名="方法"
  • v-model:实现数据的双向绑定
  • v-pre:跳过所在元素和它的子元素的编译过程,也就是把这个节点及其子节点当作一个静态节点来处理
  • v-once:模板只会在第一次更新时显示数据,此后再次更新该DOM里面引用的数据时,内容不会自动更新

v-if和v-show

v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;
v-if会控制这个 DOM 节点的存在与否。

  • 主要区别是是否渲染,当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
  • 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。所以,不推荐v-if和v-for同时使用。
  • 如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去。
v-if和v-for的优先级

v-for 具有比v-if更高的优先级

如何让CSS只在当前组件中起作用?

在组件中的 style 前面加上 scoped

<keep-alive></keep-alive> 的作用是什么?

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

如何获取dom?

ref="domName" 用法:this.$refs.domName

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

vue 文件的一个加载器,将 template/js/style 转换成 js 模块。

用途:js 可以写 es6 、 style样式可以scss 或 less template 可以加 jade

assets和static的区别

相同点: assets 和 static 两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点

不相同点:assets 中存放的静态资源文件在项目打包时,也就是运行 npm run build 时会将 assets 中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在 static 文件中跟着 index.html 一同上传至服务器。static 中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是 static 中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于 assets 中打包后的文件提交较大点。在服务器中就会占据更大的空间。

建议: 将项目中 template需要的样式文件js文件等都可以放置在 assets 中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css 等文件可以放置在 static 中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。

v-model原理

v-model是一个十分强大的指令,它可以自动让原生表单组件的值自动和你选择的值绑定,我们经常用它做双向绑定。view层输入值影响data的属性值,data属性值发生改变会更新view层的数值变化。

依赖收集:在组件初始化时,比如render function里引用到了某个响应式对象,就会触发这个对象属性的getter,这时候就会把这个render function放到这个对象的订阅者列表里(track)
响应下次去设置这个响应式对象的属性时就会触发对象属性的getter,继而调用对应的订阅者列表(trigger)

1、实现原理浅层理解:触发input事件来修改value值
v-model其实是个语法糖,它实际上是做了两步动作:

v-bind:绑定响应式数据
触发 input 事件 并传递数据 (核心和重点) input>标签有一个oninput事件,该事件类似于onchange事件,不同之处在于 oninput 事件在元素值发生变化是立即触发, onchange 在元素失去焦点时触发。

2、 深层理解:利用Object.defineProperty()数据劫持来实现。
现目前使用的很多框架,最大的优点就是可以实现数据绑定,再也不需要手动进行DOM操作了,它们实现的原理之一就是数据劫持。
3、Object.defineProperty()实现数据劫持
Object.defineProperty(obj,prop,descriptor)的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。但不能监听数组的变化。
在这里插入图片描述
在Vue中其实就是通过Object.defineProperty来劫持对象属性的setter和getter操作,并“种下”一个监听器,当数据发生变化的时候发出通知。我们完全可以控制对象属性的设置和读取。getter 函数用于在数据读取时进行依赖收集,在对应的 dep 中存储所有的 watcher;setter 则是数据更新后通知所有的 watcher 进行更新。

Object.defineProperty(a, 'b', {
  enumerable: false,
  configurable: false,
  get: function(){
    console.log('b' + '被访问');
  },
  set: function(newVal){
    console.log('b' + '被修改,新' + 'b' + '=' + newVal);
  }
});
 
a.b = 2;  // b被修改,新b=2
a.b;    // b被访问

get: 一旦目标属性被访问就会调回此方法,并将此方法的运算结果返回用户。

set:一旦目标属性被赋值,就会调回此方法。

注意:当使用了getter或setter方法,不允许使用writable和value这两个属性

v-model实际上等价于


Vue中双向数据绑定是如何实现的?

vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;核心:关于VUE双向数据绑定,其核心是 Object.defineProperty() 方法

如何优化SPA应用的首屏加载速度慢的问题?

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

vue组件间传值

组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,一般来说,组件可以有以下几种关系:
在这里插入图片描述
如上图所示,A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)。

  • ref $parent / $children 适用 父子组件通信
    ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
    parent/parent / parent/children:访问父 / 子实例
  • 父子组件传递数据props/$emit
  • EventBus ($emit / $on) 适用于 父子、隔代、兄弟组件通信」这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件
  • $emit/$on 通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级
  • attrs/listeners 适用于 隔代组件通信
    attrs:包含了父作用域中不被prop所识别(且获取)的特性绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v−bind="attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。
    listeners:包含了父作用域中的(不含.native修饰器的)v−on事件监听器。它可以通v−on="listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="listeners:包含了父作用域中的(不含.native修饰器的)v−on事件监听器。它可以通过v−on="listeners" 传入内部组件
  • provide / inject 适用于 隔代组件通信
    祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。
    provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
  • vuex适用于 父子、隔代、兄弟组件通信
    Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
    改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
    可以通过以下两个方法实现组件的双向绑定,另外,还有vue2.3新出的组件双向绑定 :number.sync=“num”
vue父组件向子组件传递数据?

通过 props

子组件像父组件传递事件?

$emit 方法

computed和watch

  • computed:
    1. 计算属性,依赖其他属性值,且值具备缓存的特性。只有它依赖的属性值发生改变,下一次获取的值才会重新计算。
    2. 当一个属性受多个属性影响的时候就需要用到computed
    3. 适用于数值计算,并且依赖于其他属性时。因为可以利用缓存特性,避免每次获取值,都需要重新计算。购物车商品结算的时候
  • watch:
    1. 当一条数据影响多条数据的时候就需要用watch
    2. 观察属性,监听属性值变动。每当属性值发生变化,都会执行相应的回调。
    3. 适用于数据变化时执行异步或开销比较大的操作。搜索数据

vue组件中data为什么必须是一个函数,key的作用

组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。

  • 因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
  • 需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。作用主要是为了高效的更新虚拟DOM。

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

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

$nextTick的使用

当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。

单页面应用(SPA)和多页面(MPA)应用区别及优缺点

  • SPA:通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。
  • MPA:就是指一个应用中有多个页面,页面跳转时是整页刷新
    单页面的优点:用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小;前后端分离;页面效果会比较炫酷(比如切换页面内容时的专场动画)。

单页面缺点:不利于seo;导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载时耗时多;页面复杂度提高很多。

vue常用修饰符

.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡;
.prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
.capture:与事件冒泡的方向相反,事件捕获由外到内;
.self:只会触发自己范围内的事件,不包含子元素;
.once:只会触发一次。

vue两个核心

数据驱动:ViewModel,保证数据和视图的一致性。
组件系统:应用类UI可以看作全部是由组件树构成的。

vue和jQuery的区别

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

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

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

SPA首屏加载慢如何解决

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

hash、history和abstract

  1. hash:监听的hashchange事件,即地址栏 URL 中的 # 符号;hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。兼容性好,支持低版本浏览器和 IE 浏览器。
  2. history:history模式监听pushstate和popstate,(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
  3. abstract:支持所有 JS 运行模式,Vue-Router 自身会对环境做校验,如果发现没有浏览器 API,路由会自动强制进入 abstract 模式。在移动端原生环境也是使用 abstract 模式。
    使用场景:
  • 一般场景下,hash 和 history 都可以,除非你更在意颜值,# 符号夹杂在 URL 里看起来确实有些不太美丽。
    history优势:
  • pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL;
  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
  • pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
  • pushState() 可额外设置 title 属性供后续使用。
    history劣势:
  • 跳转后刷新或者回跳,会报一个404的错误,找不到指定的路由,最后后端去指向正确的路由 加了/hd/xxx 去匹配是否有这个/hd/{:path} 才得以解决
Vue-router跳转和location.href有什么区别

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

vuenextTick实现原理

nextTick:在下次 DOM 更新循环结束之后执行延迟回调。常用于修改数据后获取更新后的DOM。
源码位置:vue/src/core/util/next-tick.js
按照浏览器是否支持promise->mutation-observe->setImmediate->setTimeout的顺序来实现,表现出来的效果跟setTimeout大致一样的

  1. 运用异步锁的概念,保证同一时刻任务队列中只有一个 flushCallbacks。当 pengding 为 false 的时候,表示浏览器任务队列中没有 flushCallbacks 函数;当 pengding 为 true 的时候,表示浏览器任务队列中已经放入 flushCallbacks;待执行 flushCallback 函数时,pengding 会被再次置为 false,表示下一个 flushCallbacks 可进入任务队列。
  2. 环境能力检测,选择可选中效率最高的(宏任务/微任务)进行包装执行,保证是在同步代码都执行完成后再去执行修改 DOM 等操作。
  3. flushCallbacks 先拷贝再清空,为了防止nextTick嵌套nextTick导致循环不结束。

vue源码核心

  • 模板编译compiler
  • 虚拟dom及diff
  • 虚拟dom转真实dom
  • 基于依赖收集的响应式原理

vue的diff算法

核心源码:vue/src/core/vdom/patch.js
为什么要diff、同层对比、深度优先、两端对比

  • 首先需要diff的原因是操作dom的代价是昂贵的,我们要减少操作dom所以需要对比出新老虚拟dom的最小差异点,尽可能复用原有dom
  • 因为我们很少跨层级的去移动dom,所以diff算法只会对比同一父节点下的子节点,使算法的时间复杂度是O(n)
  • 深度优先,比较新vnode找到对应的老vnode,这时会先执行patchChildren进入子节点的比较,所以是深度优先
  • 首尾两端对比法,依次把旧vnode数组的首尾分别和新vnode数组的首尾进行对比,能匹配上就进入他们子节点的对比,都匹配不上就通过key索引找新vnode数组第一个节点对应的在旧vnode数组里的index,还是找不到的话就新建一个vnode。当旧vnode数组里还有节点,而新vnode数组已经遍历完了时就remove掉对应的多出来的真实dom

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

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

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

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

RouterLink在IE和Firefox中不起作用(路由不跳转)的问题

方法一:只用a标签,不适用button标签;
方法二:使用button标签和Router.navigate方法

请说下封装 vue 组件的过程?

  1. 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。(os:思考1小时,码码10分钟,程序猿的准则。)
  2. 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
  3. 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
  4. 封装完毕了,直接调用即可.

vue初始化页面闪动问题

使用vue开发时,在vue初始化之前,由于 div 是不归 vue 管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于 {{message}} 的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。首先:在css里加上 [v-cloak] { display: none; } 。如果没有彻底解决问题,则在根元素加上 style="display: none;" :style="{display: block }"

vue更新数组时触发视图更新的方法

  1. push();
  2. pop();
  3. shift();
  4. unshift();
  5. splice();
  6. sort();
  7. reverse()

vue修改打包后静态资源路径的修改

cli2 版本:将 config/index.js 里的 assetsPublicPath 的值改为 ./ 。

build: { 
  // ... 
  assetsPublicPath:  ./ , 
  // ...  
} 

cli3版本:在根目录下新建vue.config.js 文件,然后加上以下内容:(如果已经有此文件就直接修改)

module.exports = { 
  publicPath: , // 相对于 HTML 页面(目录相同)    
} 

slot插槽

slot 插槽,可以理解为slot在组件模板中提前占据了位置。当复用组件时,使用相关的slot标签时,标签里的内容就会自动替换组件模板中对应slot标签的位置,作为承载分发内容的出口。
主要作用是复用和扩展组件,做一些定制化组件的处理。

  • 默认插槽
// 子组件
<template>
  <slot>
    <div>默认插槽备选内容</div>
  </slot>
</template>

// 父组件
<template>
  <Child>
    <div>替换默认插槽内容</div>
  </Child>
</template>
  • 具名插槽:slot 标签没有name属性,则为默认插槽。具备name属性,则为具名插槽
// 子组件
<template>
  <slot>默认插槽的位置</slot>
  <slot name="content">插槽content内容</slot>
</template>

// 父组件
<template>
   <Child>
     <template v-slot:default>
       默认...
     </template>
     <template v-slot:content>
       内容...
     </template>
   </Child>
</template>
  • 作用域插槽:子组件在作用域上绑定的属性来将组件的信息传给父组件使用,这些属性会被挂在父组件接受的对象上
// 子组件
<template>
  <slot name="footer" childProps="子组件">
    作用域插槽内容
  </slot>
</template>

// 父组件
<template>
  <Child v-slot="slotProps">
    {{ slotProps.childProps }}
  </Child>
</template>

vue.directive

Vue.directive 可以注册全局指令和局部指令。
指令定义函数提供如下钩子函数

  1. bind:指令第一次绑定到元素时调用(只调用一次)
  2. inserted: 被绑定元素插入父节点时使用(父节点存在即可调用)
  3. update:被绑定元素所在模板更新时调用,不论绑定值是否变化。通过比较更新前后的绑定值。
  4. componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
  5. unbind: 只调用一次,指令与元素解绑时调用。

项目中有涉及 一键copy、权限控制 都可以用指令的方式控制,目的就是简化我们的工作量。

vue过滤器

Vue 过滤器可用在两个地方:双花括号插值和 v-bind 表达式。
Vue3 中已经废弃这个特点。

  • 局部过滤器
<div>{{ message | formatMessage }}</div>
</template>
export default {
  filters: {
    formatMessage: function(value) {
      // 可基于源值做一些处理
      return value
    }
  }
}
  • 全局过滤器
  // 可基于源值做一些处理
  return value
})

过滤器可串联,执行顺序从左到右,第二个过滤器输入值是第一个过滤器的输出值。

<div>{{ message | formatMessage1 | formatMessage2 }}</div>

proxy与object.defineProperty优势对比

「Proxy 的优势如下:」

  • Proxy 可以直接监听对象而非属性;
  • Proxy 可以直接监听数组的变化;
  • Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是
  • Object.defineProperty 不具备的;
  • Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
  • Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
    「Object.defineProperty 的优势如下:」
  • 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue
    的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

自定义组件

  • 在components目录新建你的组件文件(smithButton.vue),script一定要export default {
  • 在需要用的页面(组件)中导入:import smithButton from ‘../components/smithButton.vue’
  • 注入到vue的子组件的components属性上面,components:{smithButton}
  • template视图view中使用,<smith-button> </smith-button>
    - smithButton命名,使用的时候则smith-button

vue.js的templete编译的理解

先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点)

  • 首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。
  • 然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)

vue项目优化

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

vue3.0新特性

  1. 检测机制的改变
    3.0 将带来基于代理 Proxy 的 observer 实现,提供全语言覆盖的反应性跟踪。这消除了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限制:
    • 只能监测属性,不能监测对象
    • 检测属性的添加和删除;
    • 检测数组索引和长度的变更;
    • 支持 Map、Set、WeakMap 和 WeakSet。
    • 新的 observer 还提供了以下特性:
  • 用于创建 observable 的公开 API。这为中小规模场景提供了简单轻量级的跨组件状态管理解决方案。
    • 默认采用惰性观察。在 2.x 中,不管反应式数据有多大,都会在启动时被观察到。如果你的数据集很大,这可能会在应用启动时带来明显的开销。在 3.x 中,只观察用于渲染应用程序最初可见部分的数据。
    • 更精确的变更通知。在 2.x 中,通过 Vue.set 强制添加新属性将导致依赖于该对象的 watcher 收到变更通知。在 3.x 中,只有依赖于特定属性的 watcher 才会收到通知。
    • 不可变的 observable:我们可以创建值的“不可变”版本(即使是嵌套属性),除非系统在内部暂时将其“解禁”。这个机制可用于冻结 prop 传递或 Vuex 状态树以外的变化。
    • 更好的调试功能:我们可以使用新的 renderTracked 和 renderTriggered 钩子精确地跟踪组件在什么时候以及为什么重新渲染
  1. 模板
    模板方面没有大的变更,只改了作用域插槽,2.x 的机制导致作用域插槽变了,父组件会重新渲染,而 3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。同时,对于 render 函数的方面,vue3.0 也会进行一系列更改来方便习惯直接使用 api 来生成 vdom 。
  2. 对象式的组件声明方式
    vue2.x 中的组件是通过声明的方式传入一系列 option,和 TypeScript 的结合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦。3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易。此外,vue 的源码也改用了 TypeScript 来写。其实当代码的功能复杂之后,必须有一个静态类型系统来做一些辅助管理。现在 vue3.0 也全面改用 TypeScript 来重写了,更是使得对外暴露的 api 更容易结合 TypeScript。静态类型系统对于复杂代码的维护确实很有必要。
  3. 其它方面的更改
    vue3.0 的改变是全面的,上面只涉及到主要的 3 个方面,还有一些其他的更改:
    • 支持自定义渲染器,从而使得 weex 可以通过自定义渲染器的方式来扩展,而不是直接 fork 源码来改的方式。
    • 支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。
    • 基于 treeshaking 优化,提供了更多的内置功能。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值