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.')