4.如何理解Vue中的单向数据流?
所有props 在其父props 和子props 之间形成单向向下绑定。父组件的更新会流向子组件,但反之则不然。
这可以防止子组件无意中更改父组件的状态,从而使应用程序的数据流难以理解。
此外,每次更新父组件时,子组件中的所有属性都会更新为最新值。这意味着您不应该更改子组件内的props。当您执行此操作时,Vue 会向浏览器控制台发出警告。
如果子组件想要更改,它只能通过$emit 调度自定义事件。父组件收到后会进行修改。
尝试修改道具: 时有两种常见情况。
该prop 用于传递初始值,子组件期望将其用作本地prop 数据。在这种情况下,我们建议您定义本地数据属性并使用该属性作为初始值。
props: [\’初始计数器\’],
data: 函数() {
返回{
counter: this.initialCounter
}
}
此属性作为原始值传递,必须进行转换。在这种情况下,建议使用此属性的值来定义计算属性。
props: [“尺寸”],
计算出: {
NormalizedSize: 函数() {
返回this.size.trim().toLowerCase()
}
}
5.compute和watch有什么区别以及使用场景?
Computed:依赖于其他属性值的计算属性,仅当依赖的属性值发生变化时才会缓存计算属性的值,下次检索计算值时将重新计算。
watch:这是一个“监视”功能,类似于特定数据的监视回调,每当监视的数据发生变化时,都会执行该回调以进行后续操作。
应用场景:
如果您需要执行数值计算并依赖其他数据,则应使用计算。这是因为您可以使用计算的缓存功能来避免每次检索该值时都必须重新计算该值。
当数据更改时需要执行异步或昂贵的操作时,应该使用监视。监视选项允许您执行异步操作(访问API)、限制操作执行的频率,并等待最终结果可用。设置中间状态。这些是计算属性无法完成的事情。
6. 如果我直接给数组项赋值,Vue 可以检测到变化吗?
由于JavaScript 的限制,Vue 无法检测到以下数组更改:
如果想直接使用索引设置数组项,例如: vm.items[indexOfItem]=newValue
如果要更改数组的长度,例如: vm.items.length=newLength
为了解决第一个问题,Vue提供了如下方法:
//Vue.set
Vue.set(vm.items,indexOfItem,newValue)
//vm.$set, Vue.set 的别名
vm.$set(vm.items,indexOfItem,newValue)
//Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
为了解决第二个问题,Vue提供了以下操作方法:
//Array.prototype.splice
vm.items.splice(newLength)
7. 讨论您对Vue 生命周期的理解。
(1)什么是生命周期?
Vue实例有一个完整的生命周期。即创建、初始化数据、编译模板、挂载Dom-渲染、更新-渲染、卸载等过程。这称为Vue 生命周期。
(2)各生命周期的作用
| 生命周期说明|
| — | — |
| beforeCreate | 创建组件实例时,组件的属性生效之前。
| 已创建| 组件已完全实例化并绑定其属性,但实际dom 尚未生成,$el 尚不可用。
| beforeMount | 在挂载开始之前调用:首次调用关联的渲染函数。
| 挂载的el 将被新创建的vm.$el 替换,并在挂载到实例后调用该钩子。
| beforeUpdate | 在更新组件数据之前调用,并在修补虚拟DOM 之前发生。
| 更新组件数据后|
| 仅出于保持活动目的而激活,并在激活组件时调用。
| 仅出于保持活动目的而停用,并在组件被销毁时调用。
| beforeDestory 在组件被销毁之前调用。
| 组件被销毁后调用。
(3)生命周期图
8、Vue中父子组件的生命周期钩子函数的执行顺序是怎样的?
Vue的父子组件生命周期钩子函数的执行顺序可以分为四个部分:
加载渲染进程
父级beforeCreate – 父级创建- 父级beforeMount – 子级beforeCreate – 子级创建- 子级beforeMount – 子级安装- 父级安装
子组件更新流程
父级更新前- 子级更新前- 子级更新- 父级更新
父组件更新流程
父级beforeUpdate – 父级已更新
销毁过程
父级beforeDestroy – 子级beforeDestroy – 子级被销毁- 父级被销毁
9. 异步请求在什么生命周期被调用?
这三个钩子函数创建数据并允许您分配从服务器返回的数据,因此您可以在created钩子函数、beforeMount和mounted钩子函数中调用它。但是,我们建议您使用您创建的钩子函数调用异步请求,因为使用您创建的钩子函数调用异步请求具有以下优点:
更快地获取服务器数据并减少页面加载时间。
ssr不支持beforeMount和mounted钩子函数,因此将它们放在created中可以保持它们的一致性。
10. 在什么阶段可以访问和操作DOM?
在调用Mounted 钩子函数之前,Vue 已经将编译好的模板挂载到页面上,因此您可以在挂载时访问和操作DOM。 vue的具体生命周期图可以参见下面。一旦了解了整个生命周期各个阶段的运作,你就不会再被生命周期相关的面试问题所困扰。
11. 父组件可以监控子组件的生命周期吗?
例如,如果你有一个父组件Parent和一个子组件Child,当父组件检测到子组件被挂载时,你可以通过写来做一些逻辑处理:
//父级.vue
子@mounted=“doSomething”/
//子.vue
安装(){
this.$emit(\”已安装\”);
}
上面需要通过$emit手动触发父组件的事件。一种更简单的方法是当父组件引用子组件时通过@hook 进行监听,如下所示。
//父级.vue
孩子@hook:mounted=“做点什么”
做一点事() {
console.log(\’父组件监听挂载的钩子函数.\’);
},
//子.vue
安装(){
console.log(\’子组件触发挂载的钩子函数.\’);
},
//上面的输出序列是:
//子组件触发挂载的钩子函数.
//父组件监听挂载的钩子函数.
当然,@hook方法不仅可以挂载,还可以监听其他生命周期事件,如创建、更新等。
12.请告诉我们您对keep-alive的理解。
keep-alive 是Vue 中的内置组件,允许您保留所包含组件的状态并避免重新渲染。它具有以下特点:
通常与路由和动态组件结合使用来缓存组件。
指定包含和排除属性。两者都支持字符串或正则表达式。 include 表示仅缓存名称匹配的组件,exclusion 表示不缓存名称匹配的组件,exclusion 优先于include。
它支持两种钩子函数:enable和disable;当组件被启用时,启用的钩子函数被触发,当组件被移除时,被禁用的钩子函数被触发。
13.为什么组件中的数据是函数?
为什么组件中的数据必须是一个函数然后返回一个对象,而在new的Vue实例中数据可以直接是一个对象呢?
//数据
数据() {
返回{
message: \”子组件\”,
childName:this.name
}
}
//新的Vue
新Vue({
el: ‘#app’,
路由器,
模板:\’\’,
组件: {应用程序}
})
组件是用来复用的,JS中的对象是引用关系,所以如果组件中的数据是对象,作用域是不分离的,子组件中的数据属性值会互相影响。当组件的data 选项为函数时,每个实例都可以维护返回对象的独立副本,组件实例之间的data 属性值不会互相影响,并且新的Vue 实例不受影响。既然是复用,那么问题就是引用对象不存在。
14.v模型的原理是什么?
Vue 项目主要使用v-model 指令创建与表单输入、文本区域和选择等元素的双向数据绑定。事实证明,v-model 本质上只是在内部用作语法糖。使用不同的输入元素引发不同的事件。
text 和textarea 元素使用value 属性和输入事件。
复选框和单选框使用选中属性和更改事件。
选择字段接收作为属性的值和作为事件的更改。
以输入表单元素为例。
相当于
在自定义组件内部时,v-model 默认使用名为value 的prop 和名为input 的事件,如下所示。
父组件:
组件:
{{价值}}
道具:{
value: 字符串
},
方法:{
测试1(){
this.$emit(\’输入\’, \’小红\’)
},
},
15.Vue组件如何通信?
Vue组件之间的通信是面试时考查的常见知识点之一。您回答这个问题的方式越多,您获得的积分就越多,并显示出您对Vue 的熟练程度。 Vue组件之间的通信仅指三种类型的通信:父子组件通信、跨代组件通信、兄弟组件通信。下面,我们分别介绍每种通信方法,并讨论该方法适用的组件间通信类型。到。
(1) props/$emit 适用于父子组件通信
由于该方法是Vue组件的基础,大多数同学都会熟悉,这里就不举例介绍了。
(2)ref和$parent/$children适用于父子组件通信
ref:当与常规DOM 元素一起使用时,引用指向DOM 元素。当在子组件中使用时,引用指向组件实例。
p
是
r
e
n
t
/
家长/
父/子:访问父/子实例。
(3)EventBus($emit/$on)适合父子、跨代、兄弟组件通信。
该方法使用一个空的Vue实例作为中央事件总线(事件中心),并使用它来触发和监听任何组件的事件,包括父子组件、分代组件和兄弟组件之间的通信。
(四)
是
t
t
r
s
/
属性/
attrs/listener 适合代际组件通信
是
t
t
r
s
:包含未包含在父范围内的项目
p
r
啊
p
已确定
(
并得到
)
特征绑定
(
C
我
是
s
s
和
s
t
y
我
e
排除
)
。如果组件没有声明任何内容
p
r
啊
p
,这包括所有父作用域绑定
(
C
我
是
s
s
和
s
t
y
我
e
排除
)
,你可以通过
v
–
乙
我
n
d
=
\’
attrs:包含父范围(不包括类和样式)中prop 无法识别(和检索)的属性绑定。如果组件没有声明props,则所有父作用域绑定(类和样式除外)都包含在此处,您可以传递v-bind=\’。
attrs:包含父范围(不包括类和样式)中prop 无法识别(和检索)的属性绑定。如果组件没有声明props,则所有父作用域绑定(类和样式除外)都包含在这里,内部组件可以通过v-bind=\’attrs\’ 传递。通常与inheritAttrs 选项结合使用。
我
我
s
t
e
n
e
r
s
: 包含父作用域的内容
(
不包含
。
n
是
t
我
v
e
修饰语
)
v
–
啊
n
事件监听器。它可以通过
v
–
啊
n
=
\’
侦听器:父范围包含v-on 事件侦听器(无.native 装饰器)。可以通过v-on=\’ 来完成。
侦听器:包含父作用域中的v-on 事件侦听器(不带.native 限定符)。可以通过v-on=\’listeners\’ 传递给内部组件。
(5) Provide/Inject适合代际组件通信
通过祖先组件中的提供者提供变量,并通过后代组件中的插入来注入变量。 Provide/Inject API虽然主要解决跨级组件之间的通信问题,但其使用场景主要是子组件获取上级组件的状态,并且跨级组件之间的关系是在配置期间建立的。和依赖注入。
(6)Vuex适合父子、隔代、兄弟姐妹
弟组件通信
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
16、你使用过 Vuex 吗?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
(1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
(2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
主要包括以下几个模块:
State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
17、使用过 Vue SSR 吗?说说 SSR?
Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记\”激活\”为客户端上完全可交互的应用程序。
即:SSR大致的意思就是vue在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的html 片段直接返回给客户端这个过程就叫做服务端渲染。
服务端渲染 SSR 的优缺点如下:
(1)服务端渲染的优点:
更好的 SEO:因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;
更快的内容到达时间(首屏加载更快):SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;
(2) 服务端渲染的缺点:
更多的开发条件限制:例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server 运行环境;
更多的服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源 (CPU-intensive – CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
如果没有 SSR 开发经验的同学,可以参考本文作者的另一篇 SSR 的实践文章《Vue SSR 踩坑之旅》,里面 SSR 项目搭建以及附有项目源码。
18、vue-router 路由模式有几种?
vue-router 有 3 种路由模式:hash、history、abstract,对应的源码如下所示:
switch (mode) {
case ‘history’:
this.history = new HTML5History(this, options.base)
break
case ‘hash’:
this.history = new HashHistory(this, options.base, this.fallback)
break
case ‘abstract’:
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== ‘production’) {
assert(false, invalid mode: ${mode})
}
}
其中,3 种路由模式的说明如下:
hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History 模式;
abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.
19、能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?
(1)hash 模式的实现原理
早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 ‘#search’:
https://www.word.com#search
hash 路由模式的实现主要是基于下面几个特性:
URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;
hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;
可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;
我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。
(2)history 模式的实现原理
HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:
window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);
history 路由模式的实现主要基于存在下面几个特性:
pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;
我们可以使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);
history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。
20、什么是 MVVM?
Model–View–ViewModel (MVVM) 是一个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和 Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由 John Gossman(同样也是 WPF 和 Silverlight 的架构师)于2005年在他的博客上发表
MVVM 源自于经典的 Model–View–Controller(MVC)模式 ,MVVM 的出现促进了前端开发与后端业务逻辑的分离,极大地提高了前端开发效率,MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。如下图所示:
(1)View 层
View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建 。
(2)Model 层
Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端提供的 api 接口。
(3)ViewModel 层
ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。
需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。
MVVM 框架实现了双向绑定,这样 ViewModel 的内容会实时展现在 View 层,前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新。
这样 View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。
我们以下通过一个 Vue 实例来说明 MVVM 的具体实现,有 Vue 开发经验的同学应该一目了然:
(1)View 层
{{message}}
Click me
(2)ViewModel 层
var app = new Vue({
el: ‘#app’,
data: { // 用于描述视图状态
message: ‘Hello Vue!’,
},
methods: { // 用于描述视图行为
showMessage(){
let vm = this;
alert(vm.message);
}
},
created(){
let vm = this;
// Ajax 获取 Model 层的数据
ajax({
url: ‘/your/server/data/api’,
success(res){
vm.message = res;
}
});
}
})
(3) Model 层
{
“url”: “/your/server/data/api”,
“res”: {
“success”: true,
“name”: “IoveC”,
“domain”: “www.cnblogs.com”
}
}
21、Vue 是如何实现数据双向绑定的?
Vue 数据双向绑定主要是指:数据变化更新视图,视图变化更新数据,如下图所示:
即:
输入框内容变化时,Data 中的数据同步变化。即 View => Data 的变化。
Data 中的数据变化时,文本节点的内容同步变化。即 Data => View 的变化。
其中,View 变化更新 Data ,可以通过事件监听的方式来实现,所以 Vue 的数据双向绑定的工作主要是如何根据 Data 变化更新 View。
Vue 主要通过以下 4 个步骤来实现数据双向绑定的:
实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
以上四个步骤的流程图表示如下,如果有同学理解不大清晰的,可以查看作者专门介绍数据双向绑定的文章《0 到 1 掌握:Vue 核心之数据双向绑定》,有进行详细的讲解、以及代码 demo 示例。
22、Vue 框架怎么实现对象和数组的监听?
如果被问到 Vue 怎么实现数据双向绑定,大家肯定都会回答 通过 Object.defineProperty() 对数据进行劫持,但是 Object.defineProperty() 只能对属性进行数据劫持,不能对整个对象进行劫持,同理无法对数组进行劫持,但是我们在使用 Vue 框架中都知道,Vue 能检测到对象和数组(部分方法的操作)的变化,那它是怎么实现的呢?我们查看相关代码如下:
/**
Observe a list of Array items.
*/
observeArray (items: Array) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i]) // observe 功能为监测数据的变化
}
}
/**
对属性进行递归遍历
*/
let childOb = !shallow && observe(val) // observe 功能为监测数据的变化
前端面试题汇总
JavaScript
性能
linux
前端资料汇总
#以上关于30道Vue面试题详解【文末送书】的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91999.html