VUE

144 阅读5分钟

VUE理解

vue是一套构建用户界面的渐进式自底向上增量开发的MVVM框架。VUE核心是为解决数据绑定问题,开发大型单页面应用和组件化只关注视图层。 核心思想:

  • 数据驱动(视图的内容随着数据的改变而改变)
  • 组件化(可以增加代码的复用性,可维护性,可测试性提高开发效率,方便重复使用,体现了高内聚低耦合)

vue的单向数据流

父级prop的更新会向下流动到子组件中,每次父组件发生更新,子组件所有的prop都会刷新为最新的值。数据从父组件传递给父组件,只能单向绑定,子组件内部不能直接修改父组件传递过来的数据。(可以用data和computed解决)

vue常用的修饰符

修饰符:

  • .lazy:改变后触发,光标离开input输入框的时候值才会改变
  • .number:将输出字符串转为number类型
  • .trim:自动过滤用户输入的首尾空格 事件修饰符
  • .stop:阻止点击事件冒泡(相当于event.stopPropagation)
  • .prevent:防止执行预设的行为(event.preventDefault)
  • .capture:添加事件监听器时使用事件捕获模式,先触发有该事件修饰符的
  • .self:只会触发自己范围内的事件,不包括子元素
  • .once:只执行一次 键盘修饰符:
  • .enter
  • .tab
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right 系统修饰符
  • .ctrl
  • .alt
  • .shift
  • .meta

VUE的生命周期

image.png

生命周期钩子函数

vue实例创建阶段

beforeCreate

vue实例刚在内存中创建,this变量不能使用,数据对象(data)和方法(methods)未初始化,watcher中的事件不能获取到

created

实例已经在内存中创建好,数据和方法已经初始化完成,但是模板未编译,页面无内容。不能操作dom节点(除非用this.$nextTick(function({})),在回调函数中操作dom),this.$el和this.$ref.xxx是undefined

beforeMounte

找到template模板,编译成render函数,转换成虚拟dom。模板编译完成,数据未挂载到页面,可以看到标签间的双花括号。 render:h=>h(App) 在beforeMounte之后和mounted之前,还有渲染render函数,它的作用是把模板渲染成虚拟dom。

mounted

模板编译完成,虚拟dom渲染成真正的dom标签,数据渲染到页面,vue实例在内存中创建完毕。一般在mounted中渲染从后端获取的数据。

VUE实例运行阶段

beforeUpdate

数据依赖改变或者用/$forceUpdate强制刷新时,对象data中的数据已经更改,虚拟dom已经重新渲染,但是页面的值还没有改变。

update

data中的数据和页面更新完毕,页面已经被重新渲染。在实际开发中,一般会用监听器watch来代替beforeUpdate和update,因为watch知道是哪一个数据发生变化。

VUE实例销毁阶段

beforeDestroy

实例销毁前使用,实例还是可用的

destroyed

VUE实例被销毁,观察者、子组件、事件监听被清除(页面数据不会消失,响应式失效)

new VUE后发生的事情

  • new VUE会调用vue原型链上的_init方法对vue实例进行初始化
  • .initLifecycle初始化生命周期,对vue实例内部的一些属性(如children、parent、isMounted)进行初始化
  • .initEvents,初始化当前实例上的一些自定义事件(vue.$on)
  • .initRender,解析slots绑定在vue实例上,绑定createElement方法在实例上
  • 完成对生命周期,自定义事件等一系列属性的初始化后,触发生命周期钩子beforeCreate
  • .initInjections,在初始化data和props之前完成依赖注入
  • .initState,完成对data和props的初始化,同时对属性完成数据劫持,内部启用监听者对数据进行监听。
  • .initProvide,对依赖注入进行解析
  • 完成对数据(state状态)的初始化,触发生命周期钩子created
  • 进入挂载阶段,将vue模板语法通过vue-loader解析成虚拟DOM树,虚拟DOM树与数据完成双向绑定,触发生命周期钩子beforeMount
  • 将解析好的虚拟DOM树通过vue渲染成真实DOM,触发生命周期钩子mounted

VUE项目列表组件中key的作用

VUE采用diff算法对比新旧虚拟节点,从而更新节点。在VUE的diff函数交叉对比中,新节点和旧节点头尾交叉对比没有结果时,会根据新节点的key去对比旧节点数组中的key,找到响应的节点(key=>index 映射)。未找到就认为是一个新增节点。没有key就会遍历查找找到对应的旧节点。map映射比遍历查找速度快 key是vnode的唯一ID,可以依靠key更准确更快的拿到oldVode中对应的vnode节点

VUE子组件为什么不可以修改父组件传递的Prop

  • 原因:单向数据流易于监测数据的流动,出现错误可以更快定位到错误发生的位置

如何监控属性修改给出警告的(setter)

初始化属性,在defineReactive时判断是否处在开发环境。如果是开发环境,在触发set时判断key是否处于updatingChildren中被修改,如果不是,说明此修改来自子组件,触发warning提示。 子组件修改的prop属于基础类型时会触发提示,无法修改父组件的数据源。基础类型赋值是值拷贝。将非基础类型赋值到key时也会触发提示,修改object的属性不会触发提示,并且会修改父组件数据源的数据

VUE双向数据绑定原理

vue通过双向数据绑定,来实现view和model的同步更新。vue的双向数据绑定主要是通过数据劫持和发布订阅模式实现的。 通过Object.defineProperty()方法来对Model数据各个属性添加访问器属性,以此实现数据劫持。当model的数据变化时,通过配置setter和getter实现对View数据更新的通知。 对文本节点的更新,使用发布订阅模式,将属性作为一个主题。为该节点设置一个订阅者对象,将这个订阅者对象加入属性主题的订阅者列表中。当model层数据发生改变时,model作为发布者向主题发出通知,主题收到通知后再向它的所有订阅者推送,订阅者收到通知后更改自己的数据。 VUE3.0采用了Proxy。

VUE的响应式原理中Object.defineProperty有什么缺陷?

  • Object.defineProperty无法监控到数组下标和长度的变化,导致通过数组下标添加元素,不能实时响应
  • Object.defineProperty只能劫持对象的属性,需要对每个对象,每个属性进行遍历。如果属性值是对象,需要深度遍历。Proxy可以劫持整个对象,并返回一个新的对象。
  • Proxy不仅可以代理对象,还可以代理数组,和动态增加的属性。

v-text、{{}}、v-html区别

{{}}和v-text将数据解析为纯文本,不能输出html,v-html可以渲染出html。
v-text指令:操作网页元素中的纯文本内容。{{}}是另一种写法 v-text与{{}}等价,{{}}叫模板插值,v-text叫指令。 在渲染数据多的时候,可能把大括号显示出来(屏幕闪动)

VUE组件间如何通信?

父子组件通信

  • props+emit
  • $refs+$parent
  • provider+inject

兄弟组件通信

  • eventBus
  • $parent $ refs

任意组件通信

vuex

v-if和v-show有什么区别

v-if

真正的条件渲染,当条件为真时才会渲染。切换时会直接对标签进行创建或销毁,不显示的标签不会加载在DOM树中。

v-show

总是渲染。切换时对标签的display属性进行切换,通过display不显示来隐藏元素。 v-if的性能开销会比v-show大,切换频繁的标签更适合使用v-show。

VUE中computed和watch的差异

  • computed是计算一个新的属性,并将该属性挂载到VUE实例上,而watch是监听已经存在且已挂载到VUE实例上的数据,所以用watch同样可以监听computed计算属性的变化。
  • computed本质是惰性求值的观察者,具有缓存性。只有在依赖变化后第一次访问computed值,才会计算新的值。watch是当数据变化就会调用执行函数。
  • 计算属性内不支持异步操作,侦听属性内支持异步操作。
  • computed的函数中都有一个get(默认,获取计算属性)和set(手动添加,设置计算属性)方法。watch属性的值可以是一个对象,接收handler回调,deep,immediate三个属性。监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些其他事情。
  • 使用场景:computed适用一个数据被多个数据影响,watch适合一个数据影响多个数据。

keep-alive组件有什么作用

keep-alive是vue的内置组件

※vue-router路由有哪些模式?

hash

后面的hash值变化,浏览器既不会服务器发出请求,也不会刷新。每次hash值得变化会触发hashchange事件。

history

利用H5中新增的pushState()和replaceState()方法。这两个方法应用于浏览器的历史记录栈,在当前已有的back,forward,go的基础之上,它们提供了对历史记录进行修改的功能。当它们执行修改时,虽然改变了当前的URL,但是浏览器不会立即向后端发送请求。

vue-cli项目中assets和static文件夹有什么区别?

共同点:都是用于存放项目中所使用的静态资源文件的文件夹 区别:assets中的文件在运行npm run build的时候会打包(压缩体积,代码格式化等)。打包之后会放到static中,static中的文件不会被打包

参考资料