Vue的一些原理总结

1、双向绑定原理Object.defineProperty()

通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情

Object.defineProperty的缺点
深度监听需要递归到底,一次性计算量大
无法监听新增属性、删除属性(要使用Vue.set Vue.delete)
无法原生监听数组,需要特殊处理

利用ES5中的Object.defineProperty结合观察者模式实现的,然后利用里面的getter和setter来实现双向数据绑定的、发布订阅模式,数据劫持

首先要对数据进行劫持监听,设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。

2、Vue3的Proxy(数据代理)
3、虚拟DOM、diff算法

jquery是直接操作dom
vue引出虚拟dom,数据改变后,虚拟dom计算节点变更->再操作真实dom->更新视图
原因:
浏览器操作dom是同步的,消耗了很多更新次数,更新完所有改变的dom,一次性渲染到页面

虚拟DOM就是为了解决浏览器性能问题而被设计出来的。如前,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

在传统的jq中,操作的都是真实的DOM,.而一个真实dom的渲染过程,要经过渲染引擎构建DOM树.构建样式表.组建成render(渲染)树的过程,要经过不断的重绘回流才能够展示给用户.
那么在直接js操作dom的过程中,比方说一个循环10次插入dom元素,其实每一次都会经历上面的过程…经历大量的重绘回流.代价特别大.性能低下.所以出现了虚拟dom

SVELTE :https://www.sveltejs.cn/ ---------下一代MVVM王者

什么是虚拟dom=====用js模拟DOM结构

<div id="app" class="container">   //dom
    <h1>虚拟dom</h1>
    <ul style="color: #42b983">
        <li>第一项</li>
        <li>第二项</li>
        <li>第三项</li>
    </ul>
</div>
{             //js模拟dom结构
  tag:'div',
  props:{id:'app',className:'container'},
  children:[
    {tag:'h1', children:'虚拟dom'},
    {tag:'ul',
      props:{style:'color:#42b983'},
      children:[
        {tag:'li',children:'第一项'},
        {tag:'li',children:'第二项'},
        {tag:'li',children:'第三项'}
      ]
    }
  ]
}

虚拟dom(snabbdom库)====https://github.com/snabbdom/snabbdom/blob/master/README.md
diff算法
diff 算法是一种通过同层的树节点进行比较的高效算法
diff 算法在很多场景下都有应用,在 vue 中,作用于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较
优点 :(1000个节点,只需要计算1000次)

  • 只比较同一层级,不会跨级比较
  • 标签名tag不同,直接删除重建,不做深度比较
  • 标签名tag相同,key相同,就认为是相同节点,不做深度比较

其有两个特点:
比较只会在同层级进行, 不会跨层级比较(降低了时间复杂度空间复杂度)
在diff比较的过程中,循环从两边向中间比较

原理:当数据发生改变时,set方法会调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应的视图
源码位置:src/core/vdom/patch.js
②重要的函数

==h函数生成虚拟dom节点

  const cnode = h('ul#list',{},[   //创建节点
    h('li.item',{},'第1项'),
    h('li.item',{},'第2项'),
    h('li.item',{},'第3项'),
  ])
  vnode包含sel,data,children,text,elm,key

==patch函数
patch函数通过init函数创建出来,patch(oldVNode,VNode),接收旧node,新node

patch(container,cnode)    //第一次渲染,vnode更新到容器中,并创建空节点
patch(vnode,newVnode);  //用新的vnode->更新老的vnode
通过sameVnode判断新旧node是否相同
	标签名与key相同:执行patchVnode函数,是同一节点,不做比较
	标签名与key不同:创建新的dom节点,移除老的domn元素

==patchVnode更新函数
//新vnode,无text,有children ==>用updateChildren更新
//新vnode,有text,无children
在这里插入图片描述
==updateChildren函数

使用sameVnode函数判断老、新开始
4、vue是如何渲染和更新的

初次渲染过程
触发响应式,监听getter、setter
执行render函数,生成vnode,patch(vnode)
更新过程
修改data,触发setter,此前getter已被监听
重新执行render函数,生成newVnode
patch(vnode,newVnode)

5、data为啥必须是函数

作用域问题,为了保证互不干扰,因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象,不要和其他组件共用一个对象。而且data也是一个闭包的经典使用常见。

6、模板编译

vue中使用render代替template
模板编译为render函数,执行render 函数返回vnode
基于vnode 再执行patch 和diff(后面会讲)
使用webpack vue-loader,会在开发环境下编译模板(重要)

7、前端路由

hash-window.onhashchange
H5 history-history.pushState 和 window.onpopstate
H5 history 需要后端支持

8、生命周期钩子

created实例挂载完毕;mounted渲染到页面完毕;updated更新数据完毕;destroyed销毁完毕

创建前 beforeCreate 、创建后created(有data,无$el)

  • beforeCreate:Vue或者组件刚刚实例化,data,methods还没有被创建
  • created :此时data和methods 已经被创建,可以使用了。模板还没有被编译。

挂载前:beforeMount, 挂载后:mounted(有data,有$el)

  • beforeMount:created 的下一个阶段。此时模板已经被编译了 但是并没有被挂到网页上。
  • mouted:模板代码已经被加载到网页中了,此时创建的所有事件都已经准备好了,网页开始运行了。

更新前: beforeUpdate、 更新后updated

  • beforeUpdate:在网页运行期间, data中的数据可能会进行更新,在这个阶段,数据只是在data中更新了,但是并没有在模板中更新,因此网页中显示的还是之前的。
  • updated:数据在 data中更新了,也在网页中更新了。

销毁前 beforeDestroy、 销毁后destroyed

  • beforeDestroy:Vue 实例或者是组件在被销毁之前执行的函数,在这一个函数中 Vue或者组件中所有的属性都是可以使用的。
  • destroyed:Vue 实例或者是组件在被销毁后执行的。此时Vue实例上所有的东西都会解绑,所有事件都会被一处,所有的子元素都会被销毁。

注:
新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销大)
actived 实例激活(该钩子在服务器端渲染期间不被调用。)
deactived 实例失效 (该钩子在服务器端渲染期间不被调用。)

父子组件生命周期
创建阶段:先父后子
挂载阶段:先父后子
更新阶段:先子后父
销毁阶段:销毁后是先子后父

父的onBeforeMount   //挂载前   先父后子
子的onBeforeMount
子的onMounted      //挂载后   先子后父
父的onMounted
子的onBeforeUpdate   //子更新阶段  
子的onUpdated
父的onBeforeUnmounted   //销毁前---先父后子
子的onBeforeUnmounted
子的onUnmounted        //销毁后----先子后父
父的onUnmounted
9、Vue的源码

源码地址:https://github.com/vuejs/core
pnpm as the package manager
npm/yarn 采用了直接平铺的方式,而 pnpm 则是采用 .pnpm 隐藏目录隐藏真实的平铺结构,在使用链接(symbollink)的方式将真实安装的目录映射到 node_modules 下

10、vuex的模块、流程、异步时action?vuex数据持久化?

vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules 5个要素,

主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态

getters相当于组件的计算属性,组件中获取到的数据做提前处理的.起到辅助函数的作用.

因为vuex中的state是存储在内存中的,一刷新就没了,例如登录状态,常见解决方案有:

①:利用H5的本地存储(localStorage,sessionStorage)

②:利用第三方封装好的插件,例如:vuex-persistedstate

③:使用vue-cookie插件来做存储

npm install vue-cookie --save 
11. SPA和MPA?

单页应用SPA是一种网络应用程序或网站的模型,它通过动态重写当前页面来与用户交互,这种方法避免了页面之间切换打断用户体验在单页应用中,所有必要的代码(HTML、JavaScript和CSS)都通过单个页面的加载而检索

多页应用MPA(MultiPage-page application),翻译过来就是多页应用在MPA中,每个页面都是一个主页面,都是独立的当我们在访问另一个页面的时候,都需要重新加载html、css、js文件

我们熟知的JS框架如react,vue,angular,ember都属于SPA

单页应用与多页应用的区别

单页面应用(SPA)多页面应用(MPA)
组成一个主页面和多个页面片段多个主页面
刷新方式局部刷新整页刷新
url模式哈希模式历史模式
SEO搜索引擎优化难实现,可使用SSR方式改善容易实现
数据传递容易通过url、cookie、localStorage等传递
页面切换速度快,用户体验良好切换加载资源,速度慢,用户体验差
维护成本相对容易相对复杂
单页应用优缺点
优点:具有桌面应用的即时性、网站的可移植性和可访问性;用户体验好、快,内容的改变不需要重新加载整个页面;良好的前后端分离,分工更明确
缺点:不利于搜索引擎的抓取;首次渲染速度相对较慢
11、mvc与mvvm

MVVM(异步通信为主) 由 Model,View,ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。

在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
在这里插入图片描述
MVC(同步通信为主):Model、View、Cofktroller
在这里插入图片描述

12、Vue-router路由?路由守卫?懒加载?replace和push的区别?

前端路由实现原理主要通过以下两种技术实现的

①利用H5的history API实现

主要通过history.pushState 和 history.replaceState来实现,不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录[发布项目时,需要配置下apache]

②利用url的hash实现

我们经常在 url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,路由里的 # 不叫锚点,我们称之为 hash,我们说的就是hash,主要利用监听哈希值的变化来触发事件 —— hashchange 事件来做页面局部更新

③abstract模式

适用于所有JavaScript环境,例如服务器端使用Node.js。如果没有浏览器API,路由器将自动被强制进入此模式。

总结:hash 方案兼容性好,而H5的history主要针对高级浏览器。

路由守卫:

①全局路由钩子 beforeEach(to,from,next) { }

②路由独享的钩子

beforeEnter(to,from,next) {
}

③组件内的钩子

beforeRouteEnter(to,from,next) {
	//…
}
beforeRouteUpdate(to,from,next) {
	//…
}
beforeRouteLeave(to,from,next) {
	//…
}

适用场景:动态设置页面标题,判断用户登录权限等

vue路由懒加载主要解决打包后文件过大的问题,事件触发才加载对应组件中的js
push与replace区别

  1. this.$router.push()
    描述:跳转到不同的url,但这个方法会向history栈添加一个记录,点击后退会返回到上一个页面。

  2. this.$router.replace()
    描述:同样是跳转到指定的url,但是这个方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。

  3. this.$router.go(n)
    相对于当前页面向前或向后跳转多少个页面,类似 window.history.go(n)。n可为正数可为负数。正数返回上一个页面

hash与history区别

13、Vue异步队列?nextTick是什么?适用场景?

异步更新队列:Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一个事件循环中发生的所以数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和DOM操作。然后,在下一个事件循环tick中,Vue刷新队列并执行实际(已去重的)工作。

因为Vue的异步更新队列,$nextTick是用来知道什么时候DOM更新完成的

vue中的nextTick主要用于处理数据动态变化后,DOM还未及时更新的问题,用nextTick就可以获取数据更新后最新DOM的变化

适用场景:

第一种:有时需要根据数据动态的为页面某些dom元素添加事件,这就要求在dom元素渲染完毕时去设置,但是created与mounted函数执行时一般dom并没有渲染完毕,所以就会出现获取不到,添加不了事件的问题,这回就要用到nextTick处理

第二种:在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法,例如:应用滚动插件better-scroll时
第三种:数据改变后获取焦点

14、vue核心是什么? vue和jquey的区别?vue与React

vue最大特点我感觉就是“组件化“和”数据驱动“

组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面是由这些组件“拼接“起来的组件树

数据驱动就是让我们只关注数据层,只要数据变化,页面(即视图层)会自动更新,至于如何操作dom,完全交由vue去完成,咱们只关注数据,数据变了,页面自动同步变化了,很方便

jquery主要是玩dom操作的“神器“,强大的选择器,封装了好多好用的dom操作方法和如何获取ajax方法 例如:$.ajax()非常好用

vue:主要用于数据驱动和组件化,很少操作dom,当然vue可能通过ref来选择一个dom或组件

vue与react

相同点:数据驱动视图、组件化、都使用 Virtual DOM

不同点:核心思想不同、组件写法差异、diff算法不同、响应式原理不同

15、v-for与v-show的区? v-for与v-if优先级

v-if和v-show都可以显示和隐藏一个元素,但有本质区别

v-if是惰性的,只是值为false就不会加载对应元素,为true才动态加载对应元素

v-show:是无论为true和为false都会加载对应html代码,但为false时用display:none隐藏不在页面显示,但为true时页面上用display:block显示其效果

适用场景:切换频繁的场合用v-show,切换不频繁的场合用v-if

v-for的优先级比v-if更高,这意味着 v-if将分别重复运行于每个 v-for循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用

16、vue组件通讯(即传值)?
  1. 父传子:主要通过props来实现的

具体实现:父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过props接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接收

  1. 子传父:主要通过$emit来实现

具体实现:子组件通过绑定事件触发函数,在其中设置this. e m i t ( ‘要派发的自定义事件’,要传递的值 ) , emit(‘要派发的自定义事件’,要传递的值), emit(要派发的自定义事件,要传递的值)emit中有两个参数一是要派发的自定义事件,第二个参数是要传递的值

然后父组件中,在这个子组件身上@派发的自定义事件,绑定事件触发的methods中的方法接受的默认值,就是传递过来的参数

  1. 兄弟之间传值有两种方法:

①:通过event bus实现
具体实现:创建一个空的vue并暴露出去,这个作为公共的bus,即当作两个组件的桥梁,在两个兄弟组件中分别引入刚才创建的bus,在组件A中通过bus. e m i t (’自定义事件名’,要发送的值)发送数据,在组件 B 中通过 b u s . emit(’自定义事件名’,要发送的值)发送数据,在组件B中通过bus. emit自定义事件名,要发送的值)发送数据,在组件B中通过bus.on(‘自定义事件名‘,function(v) { //v即为要接收的值 })接收数据

eventUus.js文件
import Vue from 'Vue'
export default new Vue()
son1:
 import eventBusfrom "./eventBus";
<kui-button @click="onson2Send">向兄弟组件传值</kui-button>
onson2Send(){
        eventBus.$emit('sendByBus',this.sockle)
}
son2:
import eventBus from "./eventBus";
mounted() {
     eventBus.$on('sendByBus',data => {
       console.log(data)
     })
}      

②:通过vuex实现
具体实现:vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules 5个要素,主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态

③:子传父,父传子实现

17、vue中methods,computed,watch的区别?

computed是多对一的关系,而watch则是一对多的关系;

methods中都是封装好的函数,无论是否有变化只要触发就会执行

computed:是vue独有的特性计算属性,可以对data中的依赖项再重新计算,得到一个新值,应用到视图中,和methods本质区别是computed是可缓存的,也就是说computed中的依赖项没有变化,则computed中的值就不会重新计算,而methods中的函数是没有缓存的。Watch是监听data和计算属性中的新旧变化。

18、Vue中,怎么设置局部样式?原理?样式穿透?

css没有局部样式的概念,vue脚手架通过实现了,即在style标签上添加scoped,

scoped的实现原理:vue通过postcss给每个dom元素添加一个以data-开头的随机自定义属性、然后css根据属性选择器添加样式

第三方库的样式穿透:

less/sass穿透问题 >>> /deep/

声明全局样式,样式加后加 !important

将样式!important至App的上方

19、 vue中,props与data优先级

props > methods>data>computed>watch

20、vue中 keep-alive 组件的作用

keep-alive:主要用于保留组件状态或避免重新渲染。

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

1、属性:

include:字符串或正则表达式。只有匹配的组件会被缓存。

exclude:字符串或正则表达式。任何匹配的组件都不会被缓存。

2、用法:

包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 相似,是一个抽象组件:它自身不会渲染一DOM 元素,也不会出现在父组件链中。

当组件在 内被切换,在 2.2.0 及其更高版本中,activated 和 deactivated生命周期 将会在 树内的所有嵌套组件中触发。

21、vue中一些可安装组件作用及用法

①vue-i18n插件
i18n:实现多语言切换功能

npm i vue-i18n -save
22、vue.config.js与webpack.config.js与vite.config.js区别

webpack.config.js是webpack的配置文件,所有使用webpack作为打包工具的项目都可以使用,vue项目使用,react项目也可用。

vue.config.js是vue项目的配置文件,专用于vue项目。通过vue.config.js中常用功能的配置,简化了配置工作,当然如果需要更专业的配置工作,两者在vue项目中是可以并存的。

vue-cli3创建的时候并不会自动创建vue.config.js,因为这个是可选项,所以一般都是修改webpack的时候才会自己创建一个vue.config.js
再然后因为vue-cli3内部高度集成了webpack,一般来说使用者不需要再去webpack做了什么,所以没有暴露webpack的配置文件,但你依然可以创建vue.config.js去修改默认的webpack。极大的简化了程序员配置webpack的工作

第一章、vue报错信息汇总

①Component name “father” should always be multi-word vue/multi-word-component-names
需要关闭eslint语法检查

const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies:true,
  lintOnSave:false,
})

②cmd出现’vue’不是内部或者外部的命令,也不是可运行的程序或者批处理文件
只有两种可能:
1,安装vue-cil 失败。
2,需要手动添加环境变量。
在C盘下,搜索vue.cmd,如果存在这个文件,那么vue-cli已经安装成功,只需要该地址存在环境变量中(系统和用户都可)。
如果不存在这个文件,
那么就可以先卸载,再安装

npm uninstall vue/cli -g
npm install -g @vue/cli
第二章、vue的开发规范

2.1、代码风格:
缩进
使用 4 个空格做为一个缩进层级,不允许使用 2 个空格或 tab 字符
单行最长限制,每行不得超过 120 个字符
属性
属性值必须用双引号
组件的属性多于 2 个时,必须分成多行,每行写一个属性;只有属性个数小于或等于 2 个时,可以写在一行内
不能有重复的属性
指令
v-for元素添加key
v-for与v-if不能同时使用,因为vue处理指令,v-for比v-if优先级高

<ul>
	<li v-for="(use,index) in activeUser" :key=index>{{use.name}}</li>
</ul>
computed:{
	activeUser:function(){
	return this.use.filter(use =>{
		return use.isActive})
	}	

data
data必须是函数
props、data、computed、methods中不能有重复的key
$emit
$emit携带的参数个数不要超过2个,多个参数时以对象形式传递,将事件参数event放在最后

第三章、一些npm 包的使用

3.1、md5

npm i md5  //2.3.0
let password = '123'
console.log(md5(password))   //202cb962ac59075b964b07152d234b70

3.2、bcryptjs
加密后,无法逆向解密,同一明文,多次加密,得到的加密结果不相同,保证安全性

npm i bcryptjs@2.4.3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值