vue
- 谈谈你怼MVVM开发模式的理解
- vue优点
- 渐进式框架的理解
- vue常用的指令
- v-if和v-show
- v-if和v-for的优先级
- 如何让CSS只在当前组件中起作用?
- `<keep-alive></keep-alive> `的作用是什么?
- 如何获取dom?
- vue-loader是什么?使用它的用途有哪些?
- assets和static的区别
- v-model原理
- Vue中双向数据绑定是如何实现的?
- 如何优化SPA应用的首屏加载速度慢的问题?
- vue组件间传值
- vue父组件向子组件传递数据?
- 子组件像父组件传递事件?
- computed和watch
- vue组件中data为什么必须是一个函数,key的作用
- 你有对 Vue 项目进行哪些优化?
- $nextTick的使用
- 单页面应用(SPA)和多页面(MPA)应用区别及优缺点
- vue常用修饰符
- vue两个核心
- vue和jQuery的区别
- delete和Vue.delete删除数组的区别
- SPA首屏加载慢如何解决
- hash、history和abstract
- Vue-router跳转和location.href有什么区别
- vuenextTick实现原理
- vue源码核心
- vue的diff算法
- 你们vue项目是打包了一个js文件,一个css文件,还是有多个文件?
- Vue2中注册在router-link上事件无效解决方法
- RouterLink在IE和Firefox中不起作用(路由不跳转)的问题
- 请说下封装 vue 组件的过程?
- vue初始化页面闪动问题
- vue更新数组时触发视图更新的方法
- vue修改打包后静态资源路径的修改
- slot插槽
- vue.directive
- vue过滤器
- proxy与object.defineProperty优势对比
- 自定义组件
- vue.js的templete编译的理解
- vue项目优化
- vue3.0新特性
谈谈你怼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这两个属性
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。这样使得我们可以方便地跟踪每一个状态的变化。
vue父组件向子组件传递数据?
通过 props
子组件像父组件传递事件?
$emit
方法
computed和watch
- computed:
- 计算属性,依赖其他属性值,且值具备缓存的特性。只有它依赖的属性值发生改变,下一次获取的值才会重新计算。
- 当一个属性受多个属性影响的时候就需要用到computed
- 适用于数值计算,并且依赖于其他属性时。因为可以利用缓存特性,避免每次获取值,都需要重新计算。购物车商品结算的时候
- watch:
- 当一条数据影响多条数据的时候就需要用watch
- 观察属性,监听属性值变动。每当属性值发生变化,都会执行相应的回调。
- 适用于数据变化时执行异步或开销比较大的操作。搜索数据
vue组件中data为什么必须是一个函数,key的作用
组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
- 因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
- 需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。作用主要是为了高效的更新虚拟DOM。
你有对 Vue 项目进行哪些优化?
- 代码层面的优化:
- v-if 和 v-show 区分使用场景
- computed 和watch 区分使用场景
- v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
- Webpack 层面的优化:
- Webpack 对图片进行压缩
- 减少 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
- 基础的 Web 技术的优化:
- 开启gzip 压缩
- 浏览器缓存
- CDN的使用
- 使用 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
- hash:监听的hashchange事件,即地址栏 URL 中的 # 符号;hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。兼容性好,支持低版本浏览器和 IE 浏览器。
- history:history模式监听pushstate和popstate,(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
- 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大致一样的
- 运用异步锁的概念,保证同一时刻任务队列中只有一个 flushCallbacks。当 pengding 为 false 的时候,表示浏览器任务队列中没有 flushCallbacks 函数;当 pengding 为 true 的时候,表示浏览器任务队列中已经放入 flushCallbacks;待执行 flushCallback 函数时,pengding 会被再次置为 false,表示下一个 flushCallbacks 可进入任务队列。
- 环境能力检测,选择可选中效率最高的(宏任务/微任务)进行包装执行,保证是在同步代码都执行完成后再去执行修改 DOM 等操作。
- 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 组件的过程?
- 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。(os:思考1小时,码码10分钟,程序猿的准则。)
- 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
- 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
- 封装完毕了,直接调用即可.
vue初始化页面闪动问题
使用vue开发时,在vue初始化之前,由于 div 是不归 vue 管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于 {{message}}
的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。首先:在css里加上 [v-cloak] { display: none; }
。如果没有彻底解决问题,则在根元素加上 style="display: none;" :style="{display: block }"
vue更新数组时触发视图更新的方法
- push();
- pop();
- shift();
- unshift();
- splice();
- sort();
- 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 可以注册全局指令和局部指令。
指令定义函数提供如下钩子函数
- bind:指令第一次绑定到元素时调用(只调用一次)
- inserted: 被绑定元素插入父节点时使用(父节点存在即可调用)
- update:被绑定元素所在模板更新时调用,不论绑定值是否变化。通过比较更新前后的绑定值。
- componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
- 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项目优化
- 代码层面优化
- v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
- webpack层面优化
- Webpack 对图片进行压缩
- 减少 ES6 转为 ES5 的冗余代码
-提取公共代码 - 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
- 基础web技术优化
- 开启 gzip 压缩
- 浏览器缓存
- CDN 的使用
- 使用 Chrome Performance 查找性能瓶颈
vue3.0新特性
- 检测机制的改变
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 钩子精确地跟踪组件在什么时候以及为什么重新渲染
- 模板
模板方面没有大的变更,只改了作用域插槽,2.x 的机制导致作用域插槽变了,父组件会重新渲染,而 3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。同时,对于 render 函数的方面,vue3.0 也会进行一系列更改来方便习惯直接使用 api 来生成 vdom 。 - 对象式的组件声明方式
vue2.x 中的组件是通过声明的方式传入一系列 option,和 TypeScript 的结合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦。3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易。此外,vue 的源码也改用了 TypeScript 来写。其实当代码的功能复杂之后,必须有一个静态类型系统来做一些辅助管理。现在 vue3.0 也全面改用 TypeScript 来重写了,更是使得对外暴露的 api 更容易结合 TypeScript。静态类型系统对于复杂代码的维护确实很有必要。 - 其它方面的更改
vue3.0 的改变是全面的,上面只涉及到主要的 3 个方面,还有一些其他的更改:- 支持自定义渲染器,从而使得 weex 可以通过自定义渲染器的方式来扩展,而不是直接 fork 源码来改的方式。
- 支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。
- 基于 treeshaking 优化,提供了更多的内置功能。