Vue面试题

1.Vue的双向数据绑定原理是什么?

答案:vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()

来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

具体步骤:

第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter,getter

这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化.

第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个

指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图.

第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:

1.在自身实例化时往属性订阅器(dep)里面添加自己

2.自身必须有一个update()方法

3.待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,

则功成身退。

第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来

监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和

Compile之间的通信桥梁,达到数据变化->视图更新:视图交互变化(input)->数据model变更的双向绑定效果.

2.请详细说下你对vue生命周期的理解

答案:总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前后。

创建前/后:beforeCreated阶段,vue实例的挂载元素$el和数据对象data

都为undefined,还未初始化。在created阶段,Vue实例的数据对象data有了,

$el还没有。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前

为虚拟DOM节点,data.message还未替换。在mounted阶段,vue实例挂载完成,

data.message成功渲染。

销毁前/后:在执行destory方法后,对data的改变不会再触发周期函数,说明此时vue

实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在.

3.封装vue组件的过程.

答案:首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,

解决了我们传统项目开发:效率低、难维护、复用性性等问题。

然后,使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。

子组件需要数据,可以在props中接收定义。而子组件修改好数据后,想把数据传递给父组件。

可以采用emit方法。

4.mvc和mvvm

答案:

MVC 模型-视图-控制器(Model-View-Controller) Model和View永远不能相互通信,

只能通过Controller传递。

Controller可以直接与Model对话(读写调用Model),Model通过Nottification和KVO机制

与Controller间接通信。

Controller可以直接与View对话,通过outlet,直接操作View,outlet直接对应到View中的控件,

View通过action向Controller报告事件的发生(如用户Touch我了)

Controller是View的直接数据源(数据很可能是Controller从Model中取得并经过加工了)。

Controller是View的代理(delegate),以同步View与Controller。

MVVM

Model - ViewModel - View

什么是MVVM:一个MVC的增强版,我们正式连接了视图和控制器,并将表示逻辑从Controller移

出放到一个新的对象里,即ViewModel。MVVM听起来很复杂,但它本质上就是一个精心优化的

MVC架构。

Model层是少不了的了,我们得有东西充当DTO(数据传输对象),当然,用字典也是可以的,

编程么,要灵活一些。Model层是比较薄的一层,如果学过Java的小伙伴的话,对JavaBean应该不陌生.

ViewModel层,就是View和Model层的粘合剂,他是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求

和其他各种各样的代码的极好的地方。说白了,就是把原来ViewController层的业务逻辑和页面逻辑

等剥离出来放到ViewModel层。

View层,就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。

5.Vue首屏加载非常慢,如何解决?

答案:Vue首屏加载非常慢.

原因:当打包应用时,将所有JavaSript代码打包在一个文件中,导致js代码非常庞大,严重影响了页面加载速度。

1.配置打包工具,将组件分别打包到不同的js代码块中

build/webpack.base.config.js

output:{

path:config.bulid.assetsRoot,

filename:'[name].js',

//新增

chunkFilename:"[name].js",

publicPath:process.env.NODE_ENV=="production"

?config.bulid.assetsPublicPath

:config.dev.assetsPublicPath

}

2.当路由请求到该组件时,才动态加载组件的内容

路由字典中,路由配置和以前完全一样

但是在引入组件对象时:

import Index from '@/views/Index.vue'

改为

const Index=()=>import('@/views/Index.vue')//仅定义函数暂未执行

//暂时不引人Index.vue

当用户在Vue中请求当前组件对应的路由地址时,由vue-router自动调用加载函数,

动态请求Index.vue组件对象

6.实现订阅/发布者模式?

答案:

var ublisher={ };

//定义发布者

publish.list=[];

//缓存列表 存放订阅者回调函数

// 增加订阅者

publisher.listen =function(fn){

publisher.list.push(fn);

// 订阅消息添加到缓存列表

}

// 发布消息

publisher.trigger =function(){

for(vari = 0,fn; fn = this.list[i++];){

var that =this

fn.apply(null,arguments);

}

}

7. 什么是虚拟DOM树:

答案:

什么是: 仅包含可能变化的节点和可能变化的属性的树结构

<body>

<div id=”app”>

<img src=”logo.png”> alt title id ….

<h1>{{uname}}</h1>id class title name

<hr>

<h2>{{score}}</h2>

</div>

{

el:”#app”,

children:[

{el:”h1”, innerText:uname},

{el:”h2”,innerText:score}

]

}

为什么: 内容少,便于快速遍历比较不同

如何发挥作用:

当data中模型变量改变时,会通知虚拟DOM树

虚拟DOM树先缓存本次的修改在元素对象上

将一批修改生成新的DOM子树和原虚拟DOM树做对比。

一旦发现不同的元素或内容,就只更新有修改的元素

虚拟DOM树中,封装了传统DOM API: createElement() appendChild() .innerHTML,避免了程序员编写大量重复的代码。

8. Vue 如何去除url中的 #

答案:

vue-router 默认使用 hash 模式,所以在路由加载的时候,项目中的 url 会自带 #。如果不想使用 #, 可以使用 vue-router 的另一种模式 history

new Router({

mode: 'history',

routes: [ ]

})

需要注意的是,当我们启用 history 模式的时候,由于我们的项目是一个单页面应用,所以在路由跳转的时候,就会出现访问不到静态资源而出现 404 的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面

9. Vue组件间如何通信

答案:

组件通信

父组件向子组件通信

子组件通过 props 属性,绑定父组件数据,实现双方通信

子组件向父组件通信

将父组件的事件在子组件中通过 $emit 触发

非父子组件、兄弟组件之间的数据传递

/*新建一个Vue实例作为中央事件总嫌*/

let event = new Vue();

/*监听事件*/

event.$on('eventName', (val) => {

//......do something

});

/*触发事件*/

event.$emit('eventName', 'this is a message.')