vue 基础
vue 是什么
是一个动态构建用户界面的渐进式 JavaScript 框架。用来创建单页应用的 web 应用框架。
优势:Vue 是一个轻量级框架,只关注图层,是一个构建数据的视图集合,大小只有十几 KB。vue 简单易学,而且通过 MVVM 思想实现了数据的双向绑定,让开发者不用再操作 dom 对象,
有更多时间去思考业务逻辑。而且 vue 是组件化的,通过组件,将单页应用中的各个模块拆分成单独的组件,提高了复用性。在更新视图的时候,还提供了虚拟节点,将新旧虚拟节点进行对
比,然后更新视图。
Vue 与 React
�
相同点:
�
�
都有组件化思想
�
�
都是数据驱动视图
�
�
都支持服务端渲染
�
�
都有虚拟 DOM
�
�
不同点:
�
�
数据流向不同。前者是双向数据流,后者是单向数据流。
�
�
数据变化的实现原理不同。前者使用的是可变的数据,后者使用的是不可变的数据。
�
�
diff 算法不同。前者使用双指针,边对比,边更新 DOM。后者主要使用 diff 队列保存需要更新的一些 DOM,然后得到 patch 树,在统一进行批量更新 DOM。
�
MVC 与 MVVM
MVC:
�
M(模型层):处理应用程序数据逻辑的部分(存数据、取数据)
�
�
V(视图层):处理数据显示的部分(页面展示、Dom 操作)
�
�
C(控制层):处理用户交互的部分(控制模型层与视图层的关联)
�
MVVM:
�
M(模型层):处理数据与业务逻辑的部分
�
�
V(视图层):负责数据展示的部分
�
�
VM(视图模型层):负责从模型层监听数据的变化从而更新视图层,用来处理用户交互操作的部分
�
两者最大区别:MVVM 实现了模型层与视图层的自动同步,当数据发生变化时,不用手动操作 DOM 元素来改变视图层的显示,而是改变了数据对应的视图层自动更新
双向数据绑定(可以看我之前写的 vue2 双向数据绑定的源码解析 https://blog.csdn.net/weixin_51642358/article/details/124878452)
vue 采用的是数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() (vue3 通过 Proxy 进行劫持)来劫持各个属性的 getter 与 setter 方法,然后再数据变动的时候,发
送消息给订阅者,触发相应的监听回调。主要步骤:
�
先使用 数据监听器 Observe 对数据对象上的所有属性都添加上 getter 和 setter 方法。这样如果数据有发生变动的话,就能拿到最新值。
�
�
再使用 compile 进行模板的解析。将模板中的变量替换成数据,然后初始化渲染视图。并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,
更新视图。
�
�
创建一个 订阅者 watcher ,在自身实例化时,往属性订阅器(dep)中添加自己,然后一旦属性变动,就会调用 dep.notice() 方法通知 对应的 watcher 调用 update() 方法进行更
新,从而更新视图。
�
�
MVVM 作为数据绑定的入口,整合了 Observe、Compile、Watcher 三者。通过 Observe 监听 模型层的数据变化,通过 Compile 来编译解析 模板指令,最后通过 Watcher 搭起 Observer
和 Compile 之间的通信桥梁,可以收到属性的变化通知并执行相应的函数,从而达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。
�
使� Object.defineProperty() 来进�数据劫持有什么缺点
在对�些属性进�操作时,使�这种�法�法拦截,�如通过下标�式修改数组数据或者给对象新增属 性,这都不能触发组件的重新渲染,因为 Object.defineProperty 不能拦截到这些操作。
更精确的来 说,对于数组��,�部分操作都是拦截不到的,只是 Vue 内部通过重写函数的�式解决了这个问题。
Vue3.0 通过使� Proxy 对对象进�代理,从�实现数据劫持。它可以完美的监听到任何方式的数据改变,唯�的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法。
computed 与 watch 区别
�
前者支持缓存,只有依赖的数据发生变化时,才会重新计算。后者不支持缓存,只要数据发生变化,就会触发相应操作。
�
�
前者不支持异步,有异步就无法监听数据变化。后者支持异步
�
�
前者一个属性由另外的属性计算而来的话,这个属性也依赖与另外的属性。
�
�
前者的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于 data 声明过,或者父组件传递过来的 props 中的数据进行计算的。
�
�
后者监听数据必须是 data 中声明的或者父组件传递过来的 props 中的数据,当发生变化时,会出大其他操作,函数有两个的参数:
�
�
immediate:组件加载立即触发回调函数
�
�
deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep 无法监听到数组和对象内部的变化。
�
�
当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用 watch
�
插槽(slot)
是子组件的一个模板标签元素。
�
默认插槽:在 slot 没有指定 name 属性值时候,一个默认的显示插槽。
�
�
具名插槽:带有 name 属性的 slot, 一个组件可以有多个具名插槽。
�
�
作用域插槽:默认插槽、具名插槽的�个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不 同点是在�组件渲染作�域插槽时,可以将�组件内部的数据传递给�组件,让�组
件根据�组件 的传递过来的数据决定如何渲染该插
�
常见的事件修饰符
�
.stop: 防止冒泡
�
�
.prevent: 阻止默认行为(链接跳转)
�
�
.once: 只会触发一次
�
�
.capture:进行事件捕捉(由外到内)
�
�
.self:只会触发自己范围内的事件,不包含子元素。
�
v-if 和 v-show 的区别
�
控制手段不同。前者动态的向 DOM 树内增加或者删除 DOM 元素来控制元素的显示与隐藏。后者通过 css 中的 display 属性来控制元素的显示与隐藏。
�
�
前者支持<template>标签。后者不支持。
�
�
编译条件不同。前者只有当第一次初始值为真的话,才会开始编译渲染。后者无论初始值,都会进行编译。
�
�
运行场景不同。前者适用于条件很少改变的情况。后者使用与频繁切换的情况。
�
�
开销不同。前者有更高的切换开销。后者有更高的初始渲染开销。
�
Vue2 给对象添加新属性,界面不刷新
Vue2 是通过 Object.defineProperty 来实现数据响应式的。(简单源码讲解:https://blog.csdn.net/weixin_51642358/article/details/124878452)在我们访问旧属性的时候,都会触发
getter 和 setter 方法,进而进行页面的刷新。但在我们添加新属性的时候,没有通过 Object.defineProperty 设置成响应式数据,所以也就无法触发事件属性的拦截,也就无法进行页面
的刷新了。
Vue3 是用 proxy 进行数据响应式的,直接动态添加新属性还是可以实现数据响应式。
解决方案:
�
Vue.set(target, propertyName/index, value ) 通过 Vue.set() 向响应式对象中添加一个 property ,并确保这个新的 property 是响应式的,而且还会触发视图的更新。
�
�
Object.assign() 直接使用这个方法添加到对象的新属性还是不会触发更新。 需要创建一个新对象,然后合并原对象和混入对象的属性
�
v-model 实现原理
v-model 实际上是一个语法糖,它的实现主要包括属性绑定和事件监听两部分
�
当作用于表单元素上
�
�
动态绑定了 input 的 value 指向了 messgae 变量,并且在触发 input 事件的时候去动态把 message 设置为当前 DOM 的 value 值
�
�
作用在组件上
�
�
在�定义组件中,v-model 默认会利�名为 value 的 prop 和名为 input 的事件
�
�
本质是一个父子组件通信的语法糖,通过 prop 和$.emit 实现。因此父组件 v-model 语法糖本质上可以修改为:
�