36、this关键字
this指向直接调用者,而非间接调用者
普通函数中的this:
在Vue所有的生命周期钩子方法(如created,mounted, updated以及destroyed)里 使用this,this指向调用它的Vue实例,即(new Vue)。
箭头函数中的this
箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window; 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this
37、Vue生命周期
vue生命周期即为一个组件从出生到死亡的一个完整周期,主要包括以下4个阶段:创建,挂载,更新,销毁
创建前:beforeCreate, 创建后:created(有data,无$el)
挂载前:beforeMount, 挂载后:mounted(有data,有$el)
更新前:beforeUpdate, 更新后:updated
销毁前:beforeDestroy, 销毁后:destroyed
新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销大)
actived 实例激活(该钩子在服务器端渲染期间不被调用。)
deactived 实例失效 (该钩子在服务器端渲染期间不被调用。
38、Vue-router路由?路由守卫?vue路由懒加载?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路由懒加载
vue路由懒加载主要解决打包后文件过大的问题,事件触发才加载对应组件中的js
replace和push的区别
this.$router.replace方法,不计入history记录,this.$router.push计入历史
39、双向绑定的原理
利用ES5中的Object.defineProperty结合观察者模式实现的,然后利用里面的getter和setter来实现双向数据绑定的、发布订阅模式,数据劫持
首先要对数据进行劫持监听,设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
40、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时
第三种:数据改变后获取焦点
41、vue核心是什么? vue和jquey的区别?vue与React
vue最大特点我感觉就是“组件化“和”数据驱动“
组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面是由这些组件“拼接“起来的组件树
数据驱动就是让我们只关注数据层,只要数据变化,页面(即视图层)会自动更新,至于如何操作dom,完全交由vue去完成,咱们只关注数据,数据变了,页面自动同步变化了,很方便
jquery主要是玩dom操作的“神器“,强大的选择器,封装了好多好用的dom操作方法和如何获取ajax方法 例如:$.ajax()非常好用
vue:主要用于数据驱动和组件化,很少操作dom,当然vue可能通过ref来选择一个dom或组件
vue与react:
相同点:数据驱动视图、组件化、都使用 Virtual DOM
不同点:核心思想不同、组件写法差异、diff算法不同、响应式原理不同
42、vue3.x新特性?
特性:引入Tree-shaking,多出setup生命周期、响应式API、响应式侦听、Composition API(组合API)、Fragment、Teleport、Suspense等
43、Vue常用的修饰符
v-on 指令常用修饰符:
.stop - 调用 event.stopPropagation(),禁止事件冒泡。
.prevent - 调用 event.preventDefault(),阻止事件默认行为。
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
v-bind 指令常用修饰符:
.prop - 被用于绑定 DOM 属性 (property)。(差别在哪里?)
.camel - (2.1.0+) 将 kebab-case 特性名转换为 camelCase. (从 2.1.0 开始支持)
.sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
v-model 指令常用修饰符:
.lazy - 取代 input 监听 change 事件
.number - 输入字符串转为数字
.trim - 输入首尾空格过滤
44、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循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用,vue3.x则v-if优先级更高
45、虚拟dom是什么,有什么用
提前使用js的方式表示出dom结构树来.存储在内存里面.同样的循环.只会最终合并执行一次,大大的提高了性能.(这个地方有点儿像js中的createElementFragment文档碎片)
而在对比的过程中.通过diff算法进行比较差异.这个比较在我理解而言就是同层比较.降低了时间复杂度空间复杂度一些什么玩意儿.最终把差异同步到真实dom上去.这就是我理解的虚拟dom
在传统的jq中,操作的都是真实的DOM,.而一个真实dom的渲染过程,要经过渲染引擎构建DOM树.构建样式表.组建成render(渲染)树,的过程,要经过不断的重绘回流才能够展示给用户.
那么在直接js操作dom的过程中,比方说一个循环10次插入dom元素,其实每一次都会经历上面的过程…经历大量的重绘回流.代价特别大.性能低下.所以出现了虚拟dom
46、diff算法
diff 算法是一种通过同层的树节点进行比较的高效算法
其有两个特点:
比较只会在同层级进行, 不会跨层级比较
在diff比较的过程中,循环从两边向中间比较
diff 算法在很多场景下都有应用,在 vue 中,作用于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较
原理:当数据发生改变时,set方法会调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应的视图
47、vue组件通讯(即传值)有哪些
第一种:父传子:主要通过props来实现的
具体实现:父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过props接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接收
第二种:子传父:主要通过$emit来实现
具体实现:子组件通过通过绑定事件触发函数,在其中设置this.$emit(‘要派发的自定义事件’,要传递的值),$emit中有两个参数一是要派发的自定义事件,第二个参数是要传递的值
然后父组件中,在这个子组件身上@派发的自定义事件,绑定事件触发的methods中的方法接受的默认值,就是传递过来的参数
第三种:兄弟之间传值有两种方法:
方法一:通过event bus实现
具体实现:创建一个空的vue并暴露出去,这个作为公共的bus,即当作两个组件的桥梁,在两个兄弟组件中分别引入刚才创建的bus,在组件A中通过bus.$emit(’自定义事件名’,要发送的值)发送数据,在组件B中通过bus.$on(‘自定义事件名‘,function(v) { //v即为要接收的值 })接收数据
方法二:通过vuex实现
具体实现:vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules 5个要素,主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态
方法三:使用全局的变量传递
在windons或document上声明或绑定数据,取值
48、vue中methods,computed,watch的区别?
computed是多对一的关系,而watch则是一对多的关系;
methods中都是封装好的函数,无论是否有变化只要触发就会执行
computed:是vue独有的特性计算属性,可以对data中的依赖项再重新计算,得到一个新值,应用到视图中,和methods本质区别是computed是可缓存的,也就是说computed中的依赖项没有变化,则computed中的值就不会重新计算,而methods中的函数是没有缓存的。Watch是监听data和计算属性中的新旧变化。
49、vue中,怎么设置局部样式?原理?样式穿透?
css没有局部样式的概念,vue脚手架通过实现了,即在style标签上添加scoped,
scoped的实现原理:vue通过postcss给每个dom元素添加一个以data-开头的随机自定义属性、然后css根据属性选择器添加样式
第三方库的样式穿透:
- less/sass穿透问题 >>> /deep/
- 声明全局样式,样式加后加 !important
- 将样式impoimport至App的上方
50、谈谈provide和inject
成对出现:provide和inject是成对出现的
作用:用于父组件向子孙组件传递数据
使用方法:provide在父组件中返回要传给下级的数据,inject在需要使用这个数据的子辈组件或者孙辈等下级组件中注入数据。
使用场景:由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject可以轻松实现跨级访问父组件的数据
provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量
需要注意的是这里不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据。