vue小结

Vue高频问题
1,vue的生命周期?
创建 挂载 跟新 卸载

2,vue实现数据双向绑定的原理
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
3,vue路由的实现原理
般源码中,都会用到 window.history 和 location.hash
Hash
url # 后面的值不会发送到后台
hash 自古都有 es6就有 不存在兼容问题
体验上不够友好 # 参数携带不了
通过拿到路由= window.location.hash
然后把内容整到页面上
History
h5新增的特性 兼容性不好 体验上是最好的
没有特殊标记 正常url路径

HTML5的pushState() 添加一条记录

Window.history.pushState(state, title, url);
popstate (js操作不会触发,浏览器的行为才会触发)
给他做一个重定向 实现页面刷新的效果
需要后台配合

replacestate 替换当前的路由栈
首先看看这个是干什么的
pushState方法就是向history中push一条记录,更改页面url,但是不刷新页面,不刷新页面,不刷新页面。不刷新页面,这点很关键,这和下面的操作很相似
window.location.href = window.location.href + ‘#a=b’
页面刷新

4,vue组件的通讯?
1.父组件传子组件

单项数据流props

2.子组件传递数据给父组件:
子组件通过事件给父组件传数据,子组件通过 e m i t ( e v e n t N a m e ) 触 发 事 件 , 父 组 件 通 过 emit(eventName)触发事件,父组件通过 emiteventNameon监听事件

3.兄弟组件间通信
①用事件发布订阅 var bus=new vue();bus. e m i t ( " i d − s e l e c t e d " , 1 ) ; b u s . emit("id-selected",1);bus. emit("idselected",1)bus.on(“id-selected”,function(id){})
②用vuex来实现

5,VueX是做什么的?
Vuex 是适用于 Vue.js 应用的状态管理库,为应用中的所有组件提供集中式的状态存储与操作,保证了所有状态以可预测的方式进行修改;
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
state: state 定义了应用状态的数据结构,同样可以在这里设置默认的初始状态。
actions:Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
mutations: 里面用于改变state的数据。
getters: Getters 在你对 store 里的数组进行查询时非常有用。

 modules:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)

命名空间
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

getautomenu.js中

action中访问action


6,Vue的路由如何传参?
方案一,通过调用$router对象的push()方法,向push()方法传递一个路由配置对象,通过params来传递参数
需要注意的是使用params必须和name属性一起使用,否则要跳转的目标路由页面无法通过params获取到传递过来的参数。

路由配置:
{
path: ‘/user’,
name: ‘user’,
component: User
}

methods:
gotoTargetView(){
this.KaTeX parse error: Expected 'EOF', got '}' at position 78: …换成path:"/user" }̲ User.vue组件: th…route.params.userName;//User.vue组件中就可以通过 r o u t e 的 p a r a m s 获 取 到 方 案 二 : 通 过 调 用 route的params获取到 方案二:通过调用 routeparamsrouter对象的push()方法,向push()方法传递一个路由配置对象,需要通过query来传递参数
methods:
gotoTargetView(){
this. r o u t e r . p u s h ( n a m e : " u s e r " , q u e r y : " u s e r N a m e " : " l h b " ) ; t h i s . router.push({name:"user",query:{"userName":"lhb"}}); this. router.push(name:"user",query:"userName":"lhb");this.router.push({path:“/user”,query:{“userName”:“lhb”}});
}
User.vue组件:
this. r o u t e . q u e r y . u s e r N a m e ; / / U s e r . v u e 组 件 中 就 可 以 通 过 route.query.userName;//User.vue组件中就可以通过 route.query.userName;//User.vueroute的query获取到

方案三:通过路由配置,配置动态路由参数
methods:
gotoTargetView() {
this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …h({path:`/user/{userName}`});
}
User.vue组件:
this. r o u t e . p a r a m s . u s e r N a m e ; / / U s e r . v u e 组 件 中 就 可 以 通 过 route.params.userName;//User.vue组件中就可以通过 route.params.userName;//User.vueroute的params获取到

7,Vue和angular的区别?
1.vue的双向数据绑定是基于 Es5中的getter和setter来实现的,而angular而是由自己实现的一套模板编译规则,需要进行 ‘脏’ 检查,vue则不需要,因此,vue性能上更高一些,但是代价是Ie9一下的浏览器无法支持。
2.vue需要提供一个el对象进行实例化,后续的所有作用范围都只能在el对象下,而angular而是整个html页面,
3.angularJs使用双向绑定,Vue在不同组件间强制使用单向数据流。这使应用的数据更加清晰结构易懂。
4.vue有更好的性能,并且非常容易优化,因为他不用脏检查。
5.vue 组件结构清晰,有自己的视图和数据逻辑。

8,Vue和SEO?
第二步我想到的解决办法是压缩合并体积比较小的js和css文件
简化代码结构,利用布局,把重要内容HTML代码放在最前。
每个页面只能出现一次H1标签,
图片一定要添加alt属性,
图片大小声明:
做好404页面,
非特殊性链接,链接地址一定要写入herf属性,做过SEO优化的人员都知道,蜘蛛目前对于js的支持很差,基本无法读取里面的链接地址。所以说用click事件是绝对不允许的,
尽少使用iframe框架。搜索引擎不会抓取到iframe里的内容,重要内容不要放在框架中。
9,Vue的优缺点?
优点:
简单:官方文档很清晰,比 Angular 简单易学。
vue做SPA应用的用户体验还是不错的,性能也比较好,开发起来也比较简单,也能实现前后端分离
vue的大量封装既是优点又是缺点,做seo那叫一个累啊,,加载效率低
vue在国内能被广泛使用的首要原因是它是基于mvvm框架做开发的

vue在国内能被广泛使用的首要原因是它是基于mvvm框架做开发的,mvvm是前端开发中一种很有影响力的模式,在mvvm中,m代表model 即模型,model中集中粗出变量以及变量的值,v代表view 即视图,集中存储html和css,vm是二者名字的结合,viewmodel,我猜测这样命名应该是找不到合适的名字替代了~~,很多人沿用mvc的controller对mvvm的vm进行中文命名,mvc也是控制器,mvvm也是控制器,说起vm可老厉害了,厉害在哪呢,又是做什么的呢,vm是衔接同步view和model的数据交互控制器,源代码中的什么数据劫持,订阅者-发布者,这么复杂的定义,就留给大神和vue项目组研究吧,我们不要没研究透,反而越来越糊涂,vue有量大系统,第一,通知系统,第二,虚拟dom树,vue对象创建后,会自动引入data对象,data就是模型数据,data中的每一个变量都会自动添加两个访问器属性_set()和_get(),调用变量实际上是调用的访问器属性,当数据发生变化后,就会调用访问器属性,调用访问器属性就会触发通知系统,vm获得通知后就对虚拟dom树进行遍历,并修改需要修改的数据,然后同步到view中,这就是mvvm或者说vue事项双向绑定的原理,虚拟dom树是vm扫描真实dom树创建的一棵极其精简的dom树,只保存变化和可能变化的元素,一点多余的东西都没有,所以遍历极快,而且还封装了dom的重复的增删改查操作,所以能极大地简化代码,这个也符合vue是一个轻量级框架的名号

10,Vue的脚手架有几种?
5种 simple,webpack-simple,vue-cli,browserify,browser-simple

11,指令keep-alive
1.搜索页面==>到搜索结果页时,搜索结果页面要重新获取数据,
2.搜索结果页面==>点击进入详情页==>从详情页返回列表页时,要保存上次已经加载的数据和自动还原上次的浏览位置。
缓存组件,vue2中提供了keep-alive。首先在我们的app.vue中定义keep-alive:

12.如何让css只在当前组件中起作用
在每一个vue组件中都可以定义各自的css,js,如果希望组件内写的css只对当前组件起作用,只需要在style中写入scoped,即:

13.Vuejs在变化检测问题
当我们在声明一个实例的过程中,所有的属性必须要在data中提前声明,只有在data中声明的属性才是响应式的。
var vm = new Vue({ data:{ a:1 } }) // vm.a 是响应的 vm.b = 2 // vm.b 是非响应的
Vue.set(vm.someObject, ‘b’, 2)
您还可以使用 vm. s e t 实 例 方 法 , 这 也 是 全 局 V u e . s e t 方 法 的 别 名 : t h i s . set 实例方法,这也是全局 Vue.set 方法的别名: this. setVue.setthis.set(this.someObject,‘b’,2)

14.关于vuejs页面闪烁{{message}} 死记
使用v-text
更新元素的 textContent。

使用v-cloak
这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。

示例:

[v-cloak] {
display: none;
}

{{ message }}
这样
不会显示,直到编译结束。 ————————————————

15.组件命名的约定
帕斯卡命名方式:ComponentName
短横线分隔:component-name
使用自定义元素的时候,两种命名方式都允许,但是当应用到dom的时候,应该使用短横线分割命名方式。
如下,两种命名方式都是正确的:

应用

15.key的使用
大家都知道,在网页中浏览器资源开销最大便是DOM节点了,DOM很慢并且非常庞大,网页性能问题大多数都是有JavaScript修改DOM所引起的。我们使用Javascript来操纵DOM,操作效率往往很低,由于DOM被表示为树结构,每次DOM中的某些内容都会发生变化,因此对DOM的更改非常快,但更改后的元素,并且它的子项必须经过Reflow / Layout阶段,然后浏览器必须重新绘制更改,这很慢的。因此,回流/重绘的次数越多,您的应用程序就越卡顿。但是,Javascript运行速度很快,虚拟DOM是放在JS 和 HTML中间的一个层。它可以通过新旧DOM的对比,来获取对比之后的差异对象,然后有针对性的把差异部分真正地渲染到页面上,从而减少实际DOM操作,最终达到性能优化的目的。
虚拟dom原理流程
简单概括有三点:

用JavaScript模拟DOM树,并渲染这个DOM树
比较新老DOM树,得到比较的差异对象
把差异对象应用到渲染的DOM树。
下面是流程图:

在这里插入图片描述

下面我们用代码一步步去实现一个流程图
S操作真实DOM的代价!
计算DOM节点坐标值等都是白白浪费的性能。
为什么需要虚拟DOM,它有什么好处?
虚拟DOM就是为了解决浏览器性能问题而被设计出来的。如前,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。
2. 使用意义

提高循环性能。key 的特殊属性主要用在 Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。有相同父元素的子元素必须有独特的key。

当我们在使用v-for进行渲染时,尽可能使用渲染元素自身属性的id给渲染的元素绑定一个key值,这样在当前渲染元素的DOM结构发生变化时,能够单独响应该元素而不触发所有元素的渲染。
————————————————
17, r o u t e 和 route和 routerouter的区别
1.router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。
2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

我们可以从vue devtools中看到每个路由对象的不同

举例:history对象

$router.push({path:‘home’});本质是向history栈中添加一个路由,在我们看来是 切换路由,但本质是在添加一个history记录
$route.path
字符串,等于当前路由对象的路径,会被解析为绝对路径,如 “/home/news” 。
$route.params
对象,包含路由中的动态片段和全匹配片段的键值对
r o u t e . q u e r y 对 象 , 包 含 路 由 中 查 询 参 数 的 键 值 对 。 例 如 , 对 于 / h o m e / n e w s / d e t a i l / 01 ? f a v o r i t e = y e s , 会 得 到 route.query 对象,包含路由中查询参数的键值对。例如,对于 /home/news/detail/01?favorite=yes ,会得到 route.query/home/news/detail/01?favorite=yesroute.query.favorite == ‘yes’ 。
$route.router
路由规则所属的路由器(以及其所属的组件)。
$route.matched
数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
$route.name
当前路径的名字,如果没有使用具名路径,则名字为空。
$route.path, $route.params, $route.name, $route.query这几个属性很容易理解,看示例就能知道它们代表的含义
方法:

$router.replace({path:‘home’});//替换路由,没有历史记录
r o u t e 是 路 由 信 息 对 象 , 包 含 了 p a t h , p a r a m s , q u e r y , h a s h , f u l l P a t h , m a t c h e d , n a m e 这 些 路 由 信 息 参 数 而 route是路由信息对象,包含了path,params,query,hash,fullPath,matched,name这些路由信息参数 而 routepathparamsqueryhashfullPathmatchednamerouter是路由实例对象包含了路由的一些跳转方法,钩子函数等

18,vue路由的钩子函数
官方称为导航守卫可以控制导航的跳转,有beforeEach,afterEach等,一般用于页面title的修改,一些需要登录才能调整页面的重定向等功能,beforeEach主要有3个参数to, from, next
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。可以控制网页的跳转

19,watch,computed,methods的区别?

20,vue中sync的用处?
.sync 只是一个双向绑定的语法糖,是指允许子组件内部修改父组件的状态。 如

v-model
v-model 绑定的是 value , 语义上是指绑定组件的值, 如 el-input 的 v-model 就是指输入的值,

两者共同点是都是双向绑定元素,不同点是 v-model 双向绑定的是value, .sync 可以双向绑定任何属性(prop)

21,vue组件怎么划分?
按着页面的框架去划分,将页面中的每一块都可以划分成为一个组件,然后从中提取公共组件,一般都是将组件分为页面组件和公共组件
指令:针对于DOM操作的一种,主要是做一些公用的处理

组件:
展示组件:没有相关的业务处理,只是单纯的展示,或者一个通用的功能(弹出框,列表显示,tab切换,控件(日期,地区,搜索,…)…)
容器组件:通过容器组件可以整合展示组件和业务组件构建成页面,通过数据的处理,将数据传递到需要使用的组件中
业务组件:有自己独立的业务逻辑,可公用,也可私用

  1. 组件的注册:
    1,全局注册(vue.component(name,() => {}))
    2,局部注册 (components选项)

react中组件是不需要注册的

  1. vue的优点:
    组件开发,单项数据流(定义,修改,只能在同一个地方),数据双向绑定。

缺点:
兼容性问题,不利于SEO搜索优化(服务端渲染)…

计算属性:定义在computed中必须有返回值,会将计算的结果进行缓存,多次调用只会执行一次,

watch:监听数据的改变执行的方法,方法名必须是需要监听的属性名或者熟悉的路径

  1. 事件处理:
    使用v-on添加事件,缩写@

    作用在vue组件上表示的是自定义事件,需要在组件内部使用$emit触发

  2. js元生中this的表示
    在函数中指的是window,
    1.在对象中的某一个方法中指的是当前对象
    2.在事件处理函数中指的是操作事件的DOM元素
    3.在定时间回调函数中指的是window(所有的回调函数中都是指window)
    但是this是可以改变的。同过(call(this,参数,参数,…),apply(this,[参数,…]),bind(this))
    bind是单纯的绑定,返回一个绑定后的新方法。applay,call是执行

  3. v-modul:本质

v-bind :属性绑定
v-on @ 事件绑定
:value=’title’ @input=’title=(e.target.value)’

  1. sync

vuex和全局变量的区别:
1,【响应式】vuex的状态存储是响应式的,当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会得到高效更新。

2,【不能直接改变store】不能直接改变store的变化,改变store中状态的唯一途径是commit mutation。方便于跟踪每一个状态的变化。
————————————————
Vuex原理 https://www.cnblogs.com/xkloveme/articles/7425915.html
31.Vue.js之computed和watch的使用与区别
计算属性computed :
使用场景:当我们拿到的值需要进行一定处理使用时,就可以使用 computed。
1.支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3. 多对一或者一对一,一般用computed
侦听属性watch

  1. 不支持缓存,数据变,直接会触发相应的操作;
    2.watch支持异步;
    3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
  2. 当一个属性发生变化时,需要执行对应的操作;一对多;
    //扩展
    如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
    computed
    使用 computed 的好处
    当我们改变 number 时,整个应用会重新渲染,用computed 不会重新进行计算,从而性能开销比较小。当新的值需要大量计算才能得到,缓存的意义就非常大。
    当我们拿到的值需要进行一定处理使用时,就可以使用 computed。
    watch
    监听某一个值,当被监听的值发生变化时,执行对应的操作
    (与computed的区别是,watch更加适用于监听某一个值的变化并做对应的操作,比如请求后台接口等,而computed适用于计算已有的值并返回结果)

watch:deep属性和immediate
监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
  immediate:组件加载立即触发回调函数执行,
  deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
不使用 deep 时,当我们改变 obj.a 的值时,watch不能监听到数据变化,默认情况下,handler 只监听属性引用的变化,也就是只监听了一层,但改对象内部的属性是监听不到的
通过使用 deep: true 进行深入观察,这时,我们监听 obj,会把 obj 下面的属性层层遍历,都加上监听事件,这样做,性能开销也会变大,只要修改 obj 中任意属性值,都会触发 handler。
注意
不要在 computed 或 watch 中,去修改所依赖的数据的值,尤其是 computed;如果这样做,可能导致一个无线循环的触发。

32.Underfined与Null的区别
用一句话总结两者的区别就是:undefined 表示一个变量自然的、最原始的状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。所以,在实际使用过程中,为了保证变量所代表的语义,不要对一个变量显式的赋值 undefined,当需要释放一个对象时,直接赋值为 null 即可。
————————————————
33.HTTP协议和HTTPS协议的区别

简单来说 HTTPS 是 HTTP 的安全版,是使用 TLS/SSL 加密的 HTTP 协议。
1.数据传输方式不同

HTTP协议是一种使用明文数据传输的网络协议。

HTTPS协议可以理解为HTTP协议的升级,就是在HTTP的基础上增加了数据加密。在数据进行传输之前,对数据进行加密,然后再发送到服务器。这样,就算数据被第三者所截获,但是由于数据是加密的,所以你的个人信息让然是安全的。这就是HTTP和HTTPS的最大区别。
2.视觉效果不同
当你使用Chrome浏览器访问一个HTTP网站的时候,你会发现浏览器会对该HTTP网站显示“不安全”的安全警告,提示用户当前所访问的网站可能会存在风险。
而假如你访问的是一个HTTPS网站时,情况却是完全不一样。你会发现浏览器的地址栏会变成绿色,企业名称会展示在地址栏中,地址栏上面还会出现一把“安全锁”的图标。这些都会给与用户很大的视觉上的安全体验。以下是EV证书在不同浏览器中的展现。
3.搜索排名不同
就是说HTTPS网站比起HTTP网站在搜索排名中更有优势(百度和谷歌两大搜索引擎都已经明确表示,HTTPS网站将会作为搜索排名的一个重要权重指标。)
总结:HTTPS网站相比起HTTP网站拥有着多种的优势,HTTP明显已经不能适应当今这个互联网时代,可以预见到HTTP在不久的将来将会全面被HTTPS所取代。

在vue文件组件中,style标签的scoped有什么作用?

vue中有一种给组件提供样式作用域的方式,让组件和组件之间不会发生冲突,原理就是通过给元素添加data-v-hashid属性的形式,让样式通过属性表达式处理达到样式隔离的目的,但是有时候也会出现问题,如果我们在一个组件中控制另一个组件的样式就不会成功,可以通过/deep/的形式突破样式作用域的隔离。

介绍一下vuex

Vuex是一个专为Vue.js应用程序开发的状态管理模式,

就是一个全局的状态管理工具,和全局变量没什么区别,唯一区别就是vuex是有规则的存储,获取,并且可以适配vue的响应式规则,并且提供可供调试的devtools。

vuex的规则就是:

  1. state: 定义状态

  2. getters:类似与组件中的computed, 可以对state中定义的状态进行过滤,计算等操作。

  3. mutations:更改Vuex的store中的状态的唯一方法是提交mutation,并在mutation中只能以同步的形式去修改state, mutations是一个对象,每一个mutation是一个函数, 函数接受state,payload作为参数,

  4. actions:异步逻辑处理的,actions是一 个对象 ,每一个action是一个函数, 函数接受context,paylo-ad作为数,在内部写ajax异步逻辑,在ajax成功或者失败,通过context.commit()去提交mutation进行state的变更。

  5. modules:如果状态特别的多的情况下,可以利用moudl-es进行模块的划分,每-个模块可以使用namespaced这个属性开启单独作用域,避免和其他模块发生冲突。

6.在组件内部如果要获取vuex的状态,以及mutation,action, getters的话vue也提供了相应的辅助函数:

mapState, mapActions, mapMutaions, mapGetters

如果遇到需要多页面,多组件共享的状态就需要使用vuex作为状态管理。

还有就是强制刷新后数据重新初始化,可以接口数据持久化(本地存储)解决这个问题‍。

Vue2.x和Vue3.x渲染器的diff算法分别说一下

简单来说,dif算法有以下过程:

同级比较,再比较子节点先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)比较都有子节点的情况(核心diff)递归比较子节点。

正常Diff两个树的时间复杂度是O(n3),但实际情况下我们很少会进行跨层级的移动DOM,所以Vue将Diff进行了优化,从O(n3)-> O(n),只有当新旧children都为多个子节点时才需要用核心的Dif算法进行同层级比较。

Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比React的Diff算法, 同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。

Vue3.x借鉴了ivi算法和inferno算法

在创建VNode时就确定其类型,以及在mount/ patch的过程中采用位运算来判断- -个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升。

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

在vue中我们使用组件进行开发,组件是复用的,一个组件如果多次复用的话就会创建多个实例,而这些实例都是同一个构造函数,如果data是对象的话,对象属于引用类型,数据之间共享,我们改变-个data值就会影响其他组件内的状态,这还是我们想要的结果,为了保证组件之间状态相互独立,所以data是必须是一个函数。‍‍

vue如何优化首屏加载速度?

优化首屏加载可以从这几个方面开始

请求优化

1, CDN

将第三方的类库放到CDN上,能够大幅度减少生产环境中的项目体积,另外CDN能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上,另外因为CDN和服务器的域名一般不是同- 一个,可以缓解同-域名并发http请 求的数量限制有效分流以及减少多余的cookie的发送(CDN上面的静态资源请求时不需要携带任何cookie)在webpack中可以通过externals配置项,将第三方的类库的弓|用地址从本地指向你提供的CDN地址

2,缓存

将长时间不会改变的第三方类库或者静态资源设置为强缓存,将max-age设置为一个非常长的时间,再将访问路径加上哈希达到哈希值变了以后保证获取到最新资源,个好的缓存策略,有助于减轻服务器的压力,并且显著的提升用户的体验

3, gzip

开启gzip压缩,通常开启gzip压缩能够有效的缩小传输资源的大小

4,http2

如果系统首屏同一时间需要加载的静态资源非常多,但是浏览器对同-域名的tcp连接数量是有限制的(chrome为6个)超过规定数量的tcp连接,则必须要等到之前的请求收到响应后才能继续发送,而http2则可以在- -个tcp连接中并发多个请求没有限制,在一些网络较差的环境开启http2性能提升尤为明显

5,懒加载.

通过import(使得ES6的模块有了动态加载的能力,让url匹配到相应的路径时,会动态加载页面组件,这样首屏的代码量会大幅减少,webpack会把动态加载的页面组件分离成单独的一个chunkjs文件

6,预渲染

由于浏览器在渲染出页面之前,需要先加载和解析相应的html,css和js文件,为此会有一段白屏的时间, 可以添加loading,或者骨架屏幕尽可能的减少白屏对用户的影响体积优化

1,合理使用第三方库

对于一些第三方ui框架,类库,尽量使用按需加载,减少打包体积

2,使用可视化工具分析打包后的模块体积

webpack-bundle- analyzer这个插件在每次打包后能够更加直观的分析打包后模块的体积,再对其中比较大的模块进行优化

3,提高代码使用率

利用代码分割,将脚本中无需立即调用的代码在代码构建时转变为异步加载的过程

4,封装

构建良好的项目架构,按照项目需求就行全局组件,插件,过滤器,指令, utils等做一 些公共封装,可以有效减少我们的代码量,而且更容易维护

资源优化

1,图片懒力加载

使用图片懒加载可以优化同一时间减少http请求开销,避免显示图片导致的画面抖动,提高用户体验

2,使用svg图标

相对于用一张图片来表示图标,svg拥有 更好的图片质量,体积更小,并且不需要开启额外的http请求

3,压缩图片

可以使用image-webpack-loader,在用户肉眼分辨不清的情况下一定程度上压缩图片

new Vue时发生了什么?

创建Vue实例的,因此首先搜索Vue的定义

function Vue (options) {
if (process.env.NODE_ENV !== ‘production’ &&
!(this instanceof Vue)
) {
warn(‘Vue is a constructor and should be called with the new keyword’);
}
this._init(options);
}
可以看到Vue构造函数的核心代码只有一行:this._init(options);因此搜索私有化_init方法。由于_init是作为this的一个方法,注意此处的this就是Vue。经过查找_init方法的定义如下:

Vue.prototype._init = function (options) {
var vm = this;
// a uid
vm._uid = uidKaTeX parse error: Expected 'EOF', got '&' at position 107: …= 'production' &̲& config.perfor…options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
);
}
/* istanbul ignore else /
if (process.env.NODE_ENV !== ‘production’) {
initProxy(vm);
} else {
vm._renderProxy = vm;
}
// expose real self
vm._self = vm;
debugger
initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, ‘beforeCreate’);
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, ‘created’);
/
istanbul ignore if */
if (process.env.NODE_ENV !== ‘production’ && config.performance && mark) {
vm._name = formatComponentName(vm, false);
mark(endTag);
measure((“vue " + (vm._name) + " init”), startTag, endTag);
}
if (vm.KaTeX parse error: Expected '}', got 'EOF' at end of input: …el) { vm.mount(vm.$options.el);
}
};
}
可以将上面的代码简化为:

Vue.prototype._init = function (options) {
var vm = this;

vm. o p t i o n s = m e r g e O p t i o n s ( o p t i o n s ∣ ∣ , v m ) ; . . . i n i t S t a t e ( v m ) ; . . . i f ( v m . options = mergeOptions(options || {}, vm); ... initState(vm); ... if (vm. options=mergeOptions(options,vm);...initState(vm);...if(vm.options.el) {
vm. m o u n t ( v m . mount(vm. mount(vm.options.el);
}

};
}

_init方法总体上做的事情其实并不多,第一项就是合并配置项。比如路由,状态管理,渲染函数。

new Vue({
store: store,
router: router,
render: h => h(App),
}).$mount(‘#app’)
然后初始化状态,initState的方法定义如下:

function initState (vm) {
vm._watchers = [];
var opts = vm.$options;
if (opts.props) { initProps(vm, opts.props); }
if (opts.methods) { initMethods(vm, opts.methods); }
if (opts.data) {
initData(vm);
} else {
observe(vm._data = {}, true /* asRootData */);
}
if (opts.computed) { initComputed(vm, opts.computed); }
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
从源码可以看出,initState就是将vue实例中的data,method,computed,watch等数据项做进一步得处理,其实就是做代理以及转化成可观测对象。

数据处理完成之后就将数据挂载到指定的钩子上:vm.options.el);

另外需要注意的是,_init方法中有一下一段代码,在上面我为来突出主线而省略了,这就是

initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, ‘beforeCreate’);
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, ‘created’);
可以看到在initState(vm)执行之前,我们执行了beforeCreate方法,在initState(vm)执行之后,我们执行了created方法。因此在beforeCreate方法中,我们无法直接引用data,method,computed,watch等在initState(vm)中才开始存在的属性。

总结:1、合并配置项。比如路由,状态管理,渲染函数

   2、初始化状态  

   3、将数据挂载到指定的钩子上:vm.options.el

        初始化生命周期,初始化事件中心,

        初始化渲染,

        初始化 data、props、

                  computed、watcher

vue中keep-alive组件的作用

在vue项目中,难免会有列表页面或者搜索结果列表页面,

点击某个结果之后,返回回来时,如果不对结果页面进行缓存,那么返回列表页面的时候会回到初始状态但是我们想要的结果是返回时这个页面还是之前搜索的结果列表,这时候就需要用到vue的 了,keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

它的作用就是实现页面的缓存提高用户的体验。它主要是靠两个函数。activated是 keep-alive组件激活时使用deactivated是keep-alive组件停用时调用;

为了防止返回列表页面的时候回到初始状态,可以是被包含的组件保留状态,或者避免重新被渲染.keep - alive在vue中主要是用来缓存组件,优化性能,使用keep - alive的组件一定要有name, 组件有两个属性,include匹配要缓存的组件,值是字符串或者数组,exclude匹配到的name命将不会缓存,如果一个组件使用了keep-alive,除非将从keep-alive实例里面找到这个组件实例并且删除,则这个组件会一直缓存。

比如:有一个列表页面和-一个详情页面,那么用户就会经常执行打开详情= >返回列表= >打开详情这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用 进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。

r o u t e 和 route 和 routerouter的区别

r o u t e 和 route和 routerouter:

$route 获取当前页面匹配的路由相关信息

       包含了当前URL解析得到的信息。包含当前的路径,参数,query对象等。

$rotuer 获取到的是当前的路由实例,用于控制路由跳转

        当导航到不同的url,可以使用$router.push方法实现,这个方法会向history里面添加一条记录,点击浏览器回退按钮的时候会回退到之前的url

$route 是 $router.currentRoute 的指针,目的就是为了方便开发者更加方便路由信息的获取  $route === $router.currentRoute‍

vue-router有几种导航钩子(导航守卫)?

第一种:全局导航钩子:

一般用来做(登录,title改变,埋点,....)

前置守卫

//单独设置每个路由的属性:

meta: { may: true }

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

    if (to.matched.some(item => item.meta.may)) {

        let id = window.localStorage.getItem("id")

        if (id) {

            next()

        } else {

            next({ name: "login" })

        }

    } else {

        next()

    }

})

注意:next 方法必须要调用,否则钩子函数无法 resolved

后置钩子

router.afterEach((to,from) => {

    if(to.meta && to.meta.title){

        document.title = to.meta.title

    }else{

        document.title = "666"

    }

})

第二种:单独路由独享钩子:不太常用

{

path: '/home',

name: 'home',

component: Home,

beforeEnter(to, from, next) {

    if (window.localStorage.getItem("id")) {

        next()

    } else {

        next({ name: "login" })

    }

}

}

第三种:组件内的钩子:

当前页面需要通过路由的进入离开做一些交互操作(表单页面放弃保存的提示)

beforeRouteEnter(to, from, next) {

    // do someting

    // 在渲染该组件的对应路由被 confirm 前调用

},

beforeRouteUpdate(to, from, next) {

    // do someting

    // 在当前路由改变,但是依然渲染该组件时调用

},

beforeRouteLeave(to, from ,next) {

    // do someting

    // 导航即将离开该组件的对应路由时被调用

}

全局解析守卫

router.beforeResolve 注册一个全局守卫,和 router.beforeEach 类似‍

vue-router 中路由的传参方式

(1)在动态路由中配置path

    {

      path : ‘/home/:id’,

      name : ‘Dome’,

      component

    }

    然后写调用的时候

    this.$router.push({path : `/describle/${id}`})

    取值: $route.parms.id

(2)通过params传参,通过name配置路由

    路由配置:

    {

      path : ‘/home’,

      name : ‘Home’,

      component : Home

    }

    this.$router.push({

      name : ‘Home’,

      params : {

        id : id

      }

    })

    获取:$route.params.id

(3)使用path来配置路由,通过query来传递参数,参数会在url后边的?id=?中显示

注意:path与params不能同时使用应用path+query

    路由配置:

    {

      path : ‘/home’,

      name : ‘Home,

      component : Home

    }

    调用:

    this.$router.push({

      path : ‘/home,

      query : {

        id : id

      }

    })

    获取:this.$route.query.id

vue-router 实现路由懒加载(动态加载路由)

写法:component:()=>import('@/components/

Home/index.vue’);

vue路由实现的原理?或vue-router原理?

原理核心就是: 更新视图但不重新请求页面。

vue-router实现单页面路由跳转,提供了三种方式:hash模式、history模式、abstract模式,根据mode参数来决定采用哪一种方式。

● hash: 使用 URL hash 值来作路由。默认模式。

● history: 依赖 HTML5 History API 和

                服务器配置。查看 HTML5 History 模式。

● abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端

hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分(/#/…),浏览器只会加载相应位置的内容,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。

HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;

由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,只需要在配置路由规则时,加入"mode: ‘history’",这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。

根据平台差异可以看出,在 Weex环境中只支持使用abstrat 模式,不过,vue-router 自身会对环境做校验,如果发现没有浏览器的 API,vue-router 会自动强制进入 abstract 模式,所以 在使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用abstract 模式。‍

参考地址:https://juejin.im/post/5bc6eb875188255c9c755df2

vue中computed的原理是什么?

要讲清楚computed原理,首先得讲vue响应式原理,

因为computed的实现是基于Watcher对象的。

那么vue的响应式原理是什么呢,众所周知,vue是基于

Object.defineProperty实现监听的。在vue初始化数据

data和computed数据过程中。会涉及到以下几个对象:

Observe对象

Dep对象

Watch对象

Observe对象是在data执行响应式时候调用,因为computed属性基于响应式属性,所以其不需要创建Observe对象。

Dep对象主要功能是做依赖收集,有个属性维护多个Watch对象,当更新时候循环调用每个Watch执行更新。

Watch对象主要是用于更新,而且是收集的重点对象。这里谈到computed计算属性,首先要知道,其有两种定义方式,-种是方法,另-种是get, set属性。而且,其内部监听的对象必须是已经定义响应式的属性,比如data的属性vuex的属性。

vue在创建computed属性时候,会循环所有计算属性,每一个计算属性会创建一个watch, 并且在通过defineProperty定义监听,在get中,计算属性工作是做依赖收集,在set中, 计算属性重要工作是重新执行计算方法,

这里需要多补充一句,因为computed是懒执行,也就是说第一次初始化之后,怀会执行计算,下一次变更执行重新计算是在set中。

另一个补充点是依赖收集的时机,computed收集时机和data一样,是在组件挂载前,但是其收集对象是自己属性对应的watch,而data本身所有数据对应一个watch‍

vue-loader 的实现原理是什么?

vue-loader是用来处理.vue后缀的vue单文件组件,

vue-loader会将单个*.vue文件内容解析成一个descriptor对象,也称为SFC (Single-FileComponents)对象。

descriptor包含template、script、 style等标签的属性和内容,方便为每种标签做对应处理。组会为每个组件生成一个唯一的哈希id, 如果某个style标签包含scoped属性,则需要进行CSS Scoped处理

对于每个标签,会根据标签属性拼接src?vue&query引用代码,中src为页面组件路径,query为一些特性的参数,比较重要的有lang、 type和scoped。如果包含lang属性,会匹配与该后缀相同的rules并应用对应的loaders,根据type执行对应的自定义loader, template将执行templateLoader、style将执行stylePostLoader。

在templateLoader中,会通过vue-template-compiler将template转换为render函数,在此过程中,会将传入的scopeld追加到每个标签的segments上,最后作为vnode的配置属性传递给createElemenet方法,在render函数调用并渲染页面时,会将scopeld属性作为原始属性渲染到页面上。

在stylePostLoader中,通过PostCSS解析style标签内容,同时通过scopedPlugin为每 个选择器追加一个[scopeld]的属性选择器‍。

vue3.0中为什么要使用Proxy,他相比以前的实现方式有什么改进?

1.Object.defineProperty只能劫持对象的属性,而Proxy是直接代理对象。

由于 Object.defineProperty 只能对属性进行劫持,需要遍历对象的每个属性。而 Proxy 可以直接代理对象。
2. Object.defineProperty对新增属性需要手动进行Observe。

由于 Object.defineProperty 劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再使用 Object.defineProperty 进行劫持。
也正是因为这个原因,使用vue给 data 中的数组或对象新增属性时,需要使用 vm.$set 才能保证新增的属性也是响应式的。
在vue的 set 方法中,对 target 是数组和对象做了分别的处理,
target 是数组时,会调用重写过的 splice 方法进行手动 Observe 。
对于对象,如果 key 本来就是对象的属性,则直接修改值触发更新,否则调用 defineReactive方法重新定义响应式对象。
(1)如果采用 proxy 实现,Proxy 通过 set(target, propKey, value, receiver) 拦截对象属性的设置,是可以拦截到对象的新增属性的。

(2)Proxy 对数组的方法也可以监测到,不需要像上面vue2.x源码中那样进行             hack。

 (3) Proxy支持13种拦截操作,这是defineProperty所不具有的

    get(target, propKey, receiver):拦截对象属性的读取,比如 proxy.foo         和 proxy['foo']。



set(target, propKey, value, receiver):

拦截对象属性的设置,比如 proxy.foo = v 或 proxy['foo'] = v ,

返回一个布尔值。



has(target, propKey):

拦截 propKey in proxy 的操作,返回一个布尔值。



deleteProperty(target, propKey):

拦截 delete proxy[propKey] 的操作,返回一个布尔值。



ownKeys(target):

拦截 Object.getOwnPropertyNames(proxy) 、      Object.getOwnPropertySymbols(proxy) 、Object.keys(proxy) 、

for…in 循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,

而 Object.keys() 的返回结果仅包括目标对象自身的可遍历属性。

getOwnPropertyDescriptor(target,propKey):

拦截 Object.getOwnPropertyDescriptor(proxy, propKey) ,返回属性的描述对象。



defineProperty(target, propKey, propDesc):

拦截Object.defineProperty(proxy,propKey,propDesc)、Object.defineProperties(proxy, propDescs) ,返回一个布尔值。



preventExtensions(target):

拦截 Object.preventExtensions(proxy) ,返回一个布尔值。



getPrototypeOf(target):

拦截 Object.getPrototypeOf(proxy) ,返回一个对象。



isExtensible(target):

拦截 Object.isExtensible(proxy) ,返回一个布尔值。



setPrototypeOf(target, proto):

拦截 Object.setPrototypeOf(proxy, proto) ,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。



apply(target, object, args):

拦截 Proxy 实例作为函数调用的操作,

比如 proxy(...args)、proxy.call(object, ...args) 、proxy.apply(...) 。



construct(target, args):

拦截 Proxy 实例作为构造函数调用的操作,比如 new proxy(...args) 。

(4)Proxy 作为新标准,长远来看,JS引擎会继续优化 Proxy ,但 getter 和 setter 基本不会再有针对性优化。

proxy缺点:

Proxy 对于IE浏览器来说简直是灾难。(不兼容)

并且目前并没有一个完整支持 Proxy 所有拦截方法的Polyfill方案,有一个google编写的 proxy-polyfill 也只支持了 get,set,apply,construct 四种拦截,可以支持到IE9+和Safari 6+。

总结:

Object.defineProperty 对数组和对象的表现一直,并非不能监控数组下标的变化,vue2.x中无法通过数组索引来实现响应式数据的自动更新是vue本身的设计导致的,不是 defineProperty 的锅。

Object.defineProperty 和 Proxy 本质差别是,defineProperty 只能对属性进行劫持,新增属性需要手动 Observe 的问题。

Proxy 作为新标准,浏览器厂商势必会对其进行持续优化,但它的兼容性也是块硬伤,并且目前还没有完整的polifill方案。

参考链接:https://blog.csdn.net/weixin_40687883/article/details/102565285
vue 中computed和watch的区别在哪里?

计算属性computed :

    1. 支持缓存,只有依赖数据发生改变,才会重新进行计算

    2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化

    3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值

    4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

    5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

侦听属性watch:

    1. 不支持缓存,数据变,直接会触发相应的操作;

    2.watch支持异步;

    3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;

    4. 当一个属性发生变化时,需要执行对应的操作一对多;

    5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,

immediate:组件加载立即触发回调函数执行,

deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。‍

监听的对象也可以写成字符串的形式

当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。这是和computed最大的区别

Vue的双向数据绑定原理?

vue实现数据双向绑定主要是:

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它让 Vue 追踪依赖,在属性被访问和修改时通知变化。

vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。‍

nextTick实现原理

在DOM更新完毕之后执行一个回调

Vue.nextTick(function () {

// DOM 更新了

})

尽管MVVM框架并不推荐访问DOM,但有时候确实会有这样的需求,尤其是和第三方插件进行配合的时候,免不了要进行DOM操作。而nextTick就提供了一个桥梁,确保我们操作的是更新后的DOM。

vue就是这样的思路,并不是用MO进行DOM变动监听,而是用队列控制的方式达到目的。

vue的数据响应过程包含:数据更改->通知Watcher->更新DOM。而数据的更改不由我们控制,可能在任何时候发生。如果恰巧发生在repaint之前,就会发生多次渲染。这意味着性能浪费,是vue不愿意看到的。

还需了解event loop的另一个重要概念,microtask.我们可以把它称为微任务

每一次事件循环都包含一个microtask队列,在循环结束后会依次执行队列中的microtask并移除,然后再开始下一次事件循环。

在执行microtask的过程中后加入microtask队列的微任务,也会在下一次事件循环之前被执行。也就是说,macrotask总要等到microtask都执行完后才能执行,microtask有着更高的优先级。

microtask的这一特性,简直是做队列控制的最佳选择啊!vue进行DOM更新内部也是调用nextTick来做异步队列控制。而当我们自己调用nextTick的时候,它就在更新DOM的那个microtask后追加了我们自己的回调函数,从而确保我们的代码在DOM更新后执行,同时也避免了setTimeout可能存在的多次执行问题。

常见的microtask有:Promise、MutationObserver、Object.observe(废弃),以及nodejs中的process.nextTick.

队列控制的最佳选择是microtask,而microtask的最佳选择是Promise.但如果当前环境不支持Promise,vue就不得不降级为macrotask来做队列控制了。

在vue2.5的源码中,macrotask降级的方案依次是:setImmediate、MessageChannel、setTimeout.

setImmediate是最理想的方案了,可惜的是只有IE和nodejs支持。

MessageChannel的onmessage回调也是microtask,但也是个新API,面临兼容性的尴尬…

所以最后的兜底方案就是setTimeout了,尽管它有执行延迟,可能造成多次渲染,算是没有办法的办法了。

总结

以上就是vue的nextTick方法的实现原理了,

总结一下就是:

vue用异步队列的方式来控制DOM更新和nextTick回调先后执行

microtask因为其高优先级特性,能确保队列中的微任务在一次事件循环前被执行完毕

因为兼容性问题,vue不得不做了microtask向macrotask的降级方案

参考链接:https://www.cnblogs.com/liuhao-web/p/8919623.html

vue组件的生命周期

** 初始化阶段的4个钩子:beforeCreate、created、beforeMount、mounted;**

beforeCreate:

1、组件创建前触发,目的是为组件的 生命周期和组件中的事件做准备;

2、没有获得数据,真实dom也没有渲染出来

3、在此阶段内可以进行数据请求,提供一次修改数据的机会

4、此阶段执行一次

Created:

1、组件创建结束

2、数据可以拿到了

3、可以进行数据请求,提供一次修改数据的机会

4、该过程执行一次

beforeMount:

1、组件挂载前

2、该阶段任务:

        判断el,判断template;

        如果el没有,那么我们需要手动挂载,如果有,那麽判        断template;

        如果template有,那么进行render函数,如果template        没有,那么通过outHTML手动书写模板;

3、数据可以获得,但是真实dom还没有渲染

4、可以进行数据请求,也提供了一次数据修改的机会

Mounted:

1、组件挂载结束

2、数据获得,真实dom也获得了

3、可以进行数据请求,也可以修改数据

4、执行一次

5、可以进行真实dom的操作了

总结:数据请求我们一般写在created钩子中,第三方库的实例化我们一般写在mounted钩子中;

运行中阶段有两个钩子:beforeUpdate、updated;

beforeUpdate:

① 更新前

② 重新渲染 VDOM , 然后通过diff算法比较两次vdom,生成            patch 补丁对象,还未渲染到页面

③ 这个钩子函数更多的是内部进行一些操作

④ 可以触发多次,只要数据更新就会触发

Updated:

① 数据更新结束

② 真实dom得到了,数据也得到了( 更新后的 )

③ 可以用于动态数据获取( 第三方库实例化 )

④ 可以触发多次,只要数据更新就会触发

销毁阶段也是有两个钩子:beforeDestroy、destroyed.

这两个钩子用法基本相同。

beforeDestroy

Destroyed

methods:{
//内部通过KaTeX parse error: Expected '}', got 'EOF' at end of input: … this.destroy();
}
},
beforeDestroy () {
//组件已经销毁,但是渲染出的真实dom结构未被销毁,手动销毁
document.querySelector(‘#app’).remove()
},
destroyed () {
console.log(‘destroyed’)
}

原文链接:https://blog.csdn.net/qq_40616529/article/details/93867644

Vue—key的使用

提高循环性能。key 的特殊属性主要用在 Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。有相同父元素的子元素必须有独特的key。

当我们在使用v-for进行渲染时,尽可能使用渲染元素自身属性的id给渲染的元素绑定一个key值,这样在当前渲染元素的DOM结构发生变化时,能够单独响应该元素而不触发所有元素的渲染。‍
原文链接https://mp.weixin.qq.com/s?__biz=MzU2Nzg5ODc4Mw==&mid=2247483917&idx=1&sn=ced506304b517329f785bf7db373fb2c&chksm=fc9765fdcbe0ecebbebceff73250a55780fc1ea9127e461cd9517c31fbfddabd5a6958c16507&xtrack=1&scene=0&subscene=10000&clicktime=1589721924&enterid=1589721924&ascene=7&devicetype=android-28&version=27000e36&nettype=WIFI&abtest_cookie=AAACAA%3D%3D&lang=zh_CN&exportkey=AxWndA%2B1s2OXP7P4Hj5xDqY%3D&pass_ticket=9g%2FTr3koxZ00PM60VBw3e0%2FGqBZ0jZTCow40hWAo32NPUfmya61JJUt%2BRFWFeQqC&wx_header=1

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值