1 ,vue响应式原理
主要通过发布订阅数据监听和数据劫持来实现的。它是从new vue开始去创建一个oberserver对象(发布者), oberserver对象会对data里面的每一个属性进行遍历结识,遍历data 里面的属性都是可能有很深的层次,forEach只能遍历浅层次的属性,在这里用到了递归,去给data 里的属性添加get和set方法同时创建了deep对象,它和data里的每一个属性一一绑定,又会去创建compile对象,在创建compile时会调用updata的方法对dom进行更新操作,还会去创建一个watcter订阅者。这个时候初始化完毕在组件去更新某些数据时,调用oberserver的set方法通知dep ,dep通知watcher,watcher调用updata的方法去更新dom,更新页面
2 ,vue中的单向数据流
在父传子的情况下,父组件的数据发生改变会通知子组件更新,子组件不能直接修改父组件的数据会报错,因为单向数据流(但是这个也是不严谨的,如果父组件传过来的是引用数据类型,以数组为例引用数据类型拷贝的是地址,修值互相更新)。在子传父的情况下,子通过emit自定义事件发送给父组件去改变刷新。
3 ,keep-alive的使用,作用
keep-alive可以包裹复用组件,缓存不活动的组件实例。在组件切换过程中将状态保留在内存中,防止重复渲染dom,减少加载事件和性能消耗,提高用户体验性。
作用:用于保留组件状态,避免重新渲染。(缓存不活动的组件实例,而不是销毁它们,keep-alive是一个抽象组件,不会渲染dom元素)
场景:例如在一个列表页面和一个详情页面,用户会经常打开详情-返回列表-打开详情这样一个高频操作,那么可以对列表组件使用keep-alive进行包裹缓存。这样用户每次返回列表的时候都能在缓存中读取快速渲染,而不是重新渲染
属性:include 匹配的组件会被缓存,exclude任何匹配的组件都不被缓存
4 ,路由的钩子
beforeEach, beforAfter, beforRouteEnter, beforRouteLeave
beforeEach: 前置路由守卫在页面跳转时做的一些操作,参数to去哪个页面,from来自哪个页面,next往下执行
beforRouteLeave:离开路由之前做的某些操作,例如在项目中清除定时器,组件中有个定时器,在路由切换的时候,可以使用beforRouteLeave将定时器进行清除,以免占用内存。
5 ,$nextTick
作用:获取异步更新后的dom, 因为vue更新dom是异步更新的,有数据变化的时候vue会开启一个异步队列,视图将会等数据变化完后统一进行更新,就是在这个时候dom 是最新的,在此可以调用nextTick获取更新后的dom
例如:在项目中添加类别,点击添加按钮弹出对话框,里面有input输入框。有个需求弹出输入框时实现自动聚焦。这时可以用到nextTick需要在dom更新完成后执行(或是用生命周期钩子函数update)
6 ,监听器watch, 应用场景,什么时候开启深度监听
侦听器可以侦听定义在data中和父组件传递子组件props接收中的数据,当数据变化的时可以在侦听器里面执行某些逻辑,
(1)开启deep深度侦听可以侦听到对象里面属性值发生的变化,例如侦听复杂的对象
(2)imnediate属性是初始化页面时候就会执行侦听器。
7 ,watch 和 computed的区别
Computed有返回值,依赖其他属性进行计算返回(定义在data中和父组件传递子组件props接收中的数据)且Computed有缓存的特性,每个计算属性里面都有一个get和set的方法Computed不支持异步。
watch是侦听器没有缓存,用来侦听数据的变化,watch中有两个参数newval和 oldval, 设置immediate:true的时候页面首次加载会执行一次监听。设置deep可以开启深度监听
支持异步。
例如:在项目中购物车的计算价格可以在Computed中做一些处理,input输入框内的数据发生变化可以利用watch侦听做一些逻辑处理
8 ,父子声明周期
父beforecreate——父created——父beforemount——子beforecreate——子created——子beforemount——子mounted——父mounted
更新和销毁阶段也是父-父-父——子-子-子-子——父
9 ,v-show和 v-if 的区别
总结:都可以用来控制元素的显示与隐藏
区别:v-show利用css的display:none/block来控制元素的显示与隐藏,v-if是动态创建和删除dom元素来达到显示与隐藏。
10 , 路由的实现方式 hash和history模式区别
url是由很多部分组成,协议,域名,端口号,路径,query,hash等。#号后面就是url中关于hash组成部分,不同的路由对应的hash是不一样的,他们都是在访问同一个静态资源index.html,监听hash部分发生变化,利用浏览器提供的hashchanage,在这个监听事件中的回调函数执行我们展示和隐藏不同的url显示。从而实现前端路由,切换页面不会刷新。
hash模式:
(1) hash模式所有的操作都是前端来完成的不需要后端的配合
(2) 通过#后面的监听url中hash部分的变化,从而实现对应的渲染逻辑
(3) Hash模式下url后面带有#
History模式:
(1) history路由模式实现主要依赖pushState与replaceState,会改变当前页面url的显示,不会刷新页面。
(2) pushState是压入浏览器的会话历史,使用history.length+1,而replaceState是替换当前的这条会话历史记录,不会增加到history.length里面
总结:
(4) History模式下url没有带#号,会改变当前页面的url显示,但不会刷新页面。如果跳转路由后再次刷新则会得到404的错误,这个错误意思是浏览器会把整个地址当成一个可访问的静态资源路径进行访问,而服务端并没有这个文件。(一般用history时需要配置nginx 告诉服务器当访问路径资源不存在时候默认会指向静态资源index.html)。Hash模式下url后面带有#号。通过#后面的监听url中hash部分的变化,从而实现对应的渲染逻辑,hash模式所有的操作都是前端来完成的不需要后端的配合
10 ,vue的生命周期
从vue的实例创建到销毁的过程就是vue的生命周期,就是从创建初始化数据,编译模板,挂载dom渲染,更新到渲染,销毁这一系列的过程。它主要分为4个阶段,创建前后,挂载前后,更新前后,销毁前后,以及特殊场景的声明周期。
beforeCreate 在new vue以后 vue内部给实例添加的一些属性和方法,data和methods初始化之前
Created data和methods初始化之后, 组件初始化完毕 ,可以发送ajax请求,注册全局事件等
beforeMount 在挂载前内存中已经编译好模板了,还没将模板渲染到页面上,此时操作不了dom
Mounted 页面已经渲染完成,可以操作dom ,一般可以在这里利用nextTick 获取更新后的dom
beforeUpdate 更新前此时数据和页面还未保持同步
Updated 更新后完成了页面的更新 数据和页面都是最新的
beforeDestroy 在销毁前 data和methods 里的方法数据,指令等还可以用,在这个阶段会解绑数据,清理定时器等。
destroyed 在销毁后所有 data和methods 方法数据,指令,定时器等都用不了,组件实例已经被销毁了。
当使用keep-alive缓存组件的时候,会增加两个钩子函数
activated 缓存的组件激活式被调用
deactivated 缓存的组件未激活时调用
errorcaptured 当捕获来自一个子组件的错误时被调用
(1)当第一次加载页面时会触发的钩子函数是:beforeCreate, created, beforeMount, mounted这几个钩子函数
(2)Created和Mounted 区别?
Created是在组件实例一旦创建完成的时候立即调用,这时候页面dom节点还未生成。
Mounted 是在dom渲染完毕后就立刻执行的,Created触发时机要比Mounted 更早一点
11 ,组件通信
(1)父子组件通信的方法有:
1- 父组件向子组件传递数据 子组件通过props来接收,props可以是数组或对象,子组件不能直接修改父组件的数据会报错,子组件通过$emit触发自定义事件,父组件监听这个自定义事件
2- 通过ref 属性给子组件设置一个名字,父组件通过parent获得父组件,这样也可以实现通信
3- 使用provider/inject , 在父组件中通过provider 提供变量,在子组件中通过inject 来将变量注入到组件中,不论子组件层级有多深,只要调用了inject 那么就可以注入provider中的数据(爷孙组件)
(2)兄弟组件通信的方法有:
1- 使用eventBus ,通过创建事件总线EventBus,新建一个 bus.js 文件,里面 new 一个 Vue()并导出,兄弟组件通过eventBus.on监听自定义事件。
2- 如果业务逻辑复杂,组件之间需要同时处理公共的数据,可以使用vuex.。 vuex 它是一个存储共享数据变量的容器,实现组件之间数据共享。state用来存放共享数据,修改数据通过mutation 的commit触发改变state的数据(同步)action主要用于后台请求的数据保存数据(异步的),通过dispatch调用mutation中的方法改变state中的数据
3- 通过 parent / $children访问父子通信
(3)谈谈vue3的组件通信有哪些?
1-在vue3中没有EventBus了可以使用一个插件mitt.js来替代,兄弟A emit触发,兄弟B on来接收
2-Vue2使用 provide / inject 传递数据不是响应式的,所以只能通过传递一个对象数据才能变成响应式
Vue3使用 provide / inject传递数据就是响应式了,这就很便捷
3-v-model 在vue2中通过.sync 让子组件修改父组件的值,但是在vue3中取消了这个修饰符,融合到v-model中去了
4-子组件通过 expose 暴露属性和方法出去
父组件通过 ref 来获取子组件的值和调用方法
12 ,v-for和v-if的优先级
v-for优先级比v-if高。本质是v-for优先执行,会创建对应的dom节点,如果v-if为false,会删除这个dom节点;这样创建后再删除,会造成页面卡顿。所以v-if和v-for放在一个标签上一起使用会造成性能浪费。可以嵌套使用把v-if放到外层template标签上,v-for放到里面的标签上。
Vue3是v-if比v-for优先级高。
13, data 为什么是函数
因为怕在组件复用的时候回造成数据污染,所以data必须是函数。我们所封装的组件都是可复用的,data是函数的话会有函数作用域,返回的对象都是独立的,是新的data。在复用组件的时候修改数据互相不影响
14, vue 数据响应式的原理(vue数据双向绑定的原理)
vue数据双向绑定的原理是基于mvvm的viewmodel,它上面会有一个数据双向绑定和事件监听。数据双向绑定是通过object.definepropty里面的get和set去定义data中的数据,每一个属性都会自动绑定get和set的方法,然后第一次渲染到那个模板渲染到页面的时候都会触发get方法,当去修改数据的时候都会触发set方法。数据劫持observer他会去劫持data中的属性,dep订阅器与data中的属性一一对应。如果属性发生变化,就会去通知订阅者watcher,看看是否需要更新,watcher就会通知dom树,虚拟dom 会利用diff算法生成新的dom树,然后进行比较,发现不一样的节点,就把新的节点更新到真实的dom树上面,调用updater方法去更新页面
15, 什么是虚拟dom
虚拟dom 就是js 对象,可以理解为它是真实DOM的抽象。如果我们直接去操作DOM 性能低。虚拟DOM利用了diff算法比较两颗虚拟dom 树的差异,发现不一样的地方进行修改,统一更新到真实的dom树上面去。
16 ,vue自定义指令
你需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令: 可以获取标签, 扩展额外的功能
全局注册在main.js 用vue.directidirectivesve('指令名',{inserted(el){}}
局部注册在当前的组件内 directives:{指令名',{inserted(el){}}
// 目标: 创建 "自定义指令", 让输入框自动聚焦
// 1. 创建自定义指令
// 全局 / 局部
// 2. 在标签上使用自定义指令 v-指令名
// 注意:
// inserted方法 - 指令所在标签, 被插入到网页上触发(一次)
// update方法 - 指令对应数据/标签更新时, 此方法执行
17 ,vue的key 的作用
(1)vue的key 主要作用就是为了高效的更新虚拟DOM。
(2)vue的key 一般搭配v-for ,v-for 一般用到列表渲染。如果在组件中使用v-for ,必须使用key,因为它是唯一标识,通过key 使diff 的操作更加准确和快速定位到需要更新的虚拟dom 上。v-for一般采取的是就地复用策略, 通过key给每个节点做一个唯一标识,diff算法就可以正确识别该节点,找到正确的位置插入新节点。
(3)优点是可以减少对DOM的操作,不提倡key用index作为值,因为Index会导致vue复用错误的旧子节点。
18 ,说一说vuex
嗯 vuex 就是一个状态资源管理器,它可以存一些你想要全局使用的数据,它有6个核心的的属性,分别是state,mutation,action,getter,还有一个module模块,我们一般是在state里面定义我们所需要管理的数据,Mutation就是一个唯一可以修改state的同步的方法,可以直接调用这个同步方法去修改state,然后action的话可以做一些异步操作,然后在action里面的话,你不能直接去操作那个state的数据,要通过mutation去调用同步的方法,间接的去操作那个state的数据,getter用于对store中的数据进行加工处理形成新的数据,类似于vue中的计算属性,store中数据变化了,getter的数据也会跟着变化。如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护,这个时候可以用module,module可以将 store分割成模块,每个模块中拥有自己的 state、mutation、action 和 gette。通常情况都是要封装一下,然后用到的页面引入。
19 ,vue的指令有哪些
v-model 常用于表单元素实现数的据绑定
v-for 可以根据数组的长度来循环渲染数据
v-show 显示内容
v-hide 隐藏内容;
v-if 根据条件渲染,创建或销毁dom元素
v-bind:简写为:,动态绑定一些元素的属性,类型可以是:字符串、对象或数组。
v-on 给标签绑定事件,可以缩写为@,例如绑定一个点击函数 函数必须写在 methods 里面;
v-text 解析文本;
v-html 解析 html 标签;
20 , vue的路由传参
(1) 路由传参有两种 :编程式router.push和声明式传递参数的方式有params和query
query方式传参和接收参数:利用this.route接收参数
params方式传参和接收参数: 利用 this.route .params.id获取参数
params 只能用name 引入路由,如写成path ,接收参数的页面会是undefined
query相当于get 请求,压面跳转的时候,可以在地址栏上面看到参数,而params 相当于post请求,参数不会在地址栏中显示
(2)route的区别
router 。$route相当于当前正在跳转的路由对象 ,局部的路由对象,里面可以获取name,query,params,path