Vue
1,vue的生命周期?
vue的生命周期主要分为几个简单,数据初始化,dom挂载,数据更新,组件卸载,在一个就是开启了组件缓存的时候,会有组件启用和组件停用阶段,每个阶段都去前后两个钩子除了缓存的那俩
数据初始化阶段
beforeCreate
:在实例初始化之后,数据观测 (data observer
) 和 event/watcher
事件配置之前被调用。
created
:实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测 (data observer
),属性和方法的运算,watch/event
事件回调。然而,挂载阶段还没开始,$el
属性目前不可见。
dom
挂载阶段
beforeMount
:在挂载开始之前被调用:相关的 render
函数首次被调用。
mounted:el
被新创建的 vm.$el
替换,并挂载到实例上去之后调用该钩子。如果 root
实例挂载了一个文档内元素,当 mounted
被调用时 vm.$el
也在文档内。
mounted
不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick
替换掉 mounted
数据跟新阶段
beforeUpdate
:数据更新时调用,发生在虚拟 DOM
重新渲染和打补丁之前。
updated
:由于数据更改导致的虚拟 DOM
重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM
已经更新,所以你现在可以执行依赖于 DOM
的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher
取而代之。
updated
不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick
替换掉 updated
:
缓存启用的时候会有下面两个钩子
activated
:keep-alive
组件激活时调用。
deactivated
:keep-alive
组件停用时调用。
组件卸载的时候:
beforeDestroy
:实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed:Vue
实例销毁后调用。调用后,Vue
实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
2,vue实现数据双向绑定的原理
vue
实现数据双向绑定主要是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。具体话其实就是通过Obeject.defineProperty()
中的setter
和getter
来监听属性变动实现Observer
进行数据的监听然后就是通知订阅者,那么订阅者其实就是简单的一个数组,这个数组中的内容就是我门使用了的一个数据的集合,使用了的数据可以通过getter
得到,其实就是在调用的时候给数组里面添加一个订阅者这样就是实现了一个Watcher
(需要监听的数据的集合),然后在实现一个Compile
其作用就是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图,其实vue的数据双向绑定就是MVVM作为数据绑定的入口,整合Observer、Compile
和Watcher
三者,通过Observer
来监听自己的model
数据变化,通过Compile
来解析编译模板指令,最终利用Watcher
搭起Observer
和Compile
之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input
) -> 数据model变更的双向绑定效果。
3,vue路由的实现原理
在vue中路由主要有 hash
与History interface
两种方式实现前端路由,单页路由的特点就是采用前端路由系统,通过改变URL,在不重新请求页面的情况下,更新页面视图。目前在浏览器环境中这一功能的实现主要有两种方式:hash
和History interface
,这两种模式的实现分别是
先说hash
,在浏览器的url
中hash(“#”)
符号的本来作用是加在URL
中指示网页中的位置:#符号本身以及它后面的字符称之为hash
,可通过window.location.hash
属性读取。它具几个特点就是:hash虽然出现在URL中,但不会被包括在HTTP
请求中。它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash
不会重新加载页面,并且可以为hash
的改变添加hashchange
监听事件,在一个就是每一次改变hash(window.location.hash)
,都会在浏览器的访问历史中增加一个记录,我就可以通过他的这几个特点实现一个hash
模式的单页路由,通过对location.hash
的修改实现push
方法(跳转页面),通过对location.href
的修改实现replace()
方法,通过对hashchange
事件的监听实现页面跳转后的数据更新
而History
模式则是完全采用了h5的新特性,从HTML5开始,History interface提供了两个新的方法:pushState(), replaceState()
使得我们可以对浏览器历史记录栈进行修改,以及popState
事件可以监听到状态的变更
不过history
模式有一个问题就是
对于单页应用来讲,理想的使用场景是仅在进入应用时加载index.html,后续在的网络操作通过Ajax完成,不会根据URL重新请求页面,但是如果用户直接在地址栏中输入并回车,浏览器重启重新加载的时候history模式则会将URL修改得就和正常请求后端的URL一样,在此情况下重新向后端发送请求,如后端没有配置对应 的路由处理,则会返回404错误。这种问题的解决,一般情况下我们都是在后端进行配置,将所有的路由请求都指向index.html文件
4,vue组件的通讯?
1.父组件传子组件
单项数据流props
使用refs
访问子组件
使用$parent
访问父组件
使用$children
访问子组件
使用$root
访问当前组件树的根 Vue
实例
在template
元素使用scope
可以访问到子组件中slot
元素的属性值 要13k
2.子组件传递数据给父组件:
子组件通过事件给父组件传数据,子组件通过$emit(eventName)
触发事件,父组件通过$on
监听事件
3.兄弟组件间通信
①用事件发布订阅
var bus=new vue();
bus.$emit("id-selected",1);
bus.$on("id-selected",function(id){})
②用vuex来实现
5,VueX是做什么的?
vue components(组件)
-> action(只能通过 dispatch 调用,与此同时可以异步与后端的 API 做交互)
-> mutations(只能通过 action 发起 commit 调用,此时开发工具可以监测到数据的流动)
-> state (mutations 传递修改过的状态到 state)
-> state 自动同步到视图
Vuex
是适用于 Vue.js
应用的状态管理库,为应用中的所有组件提供集中式的状态存储与操作,保证了所有状态以可预测的方式进行修改;
state: state
定义了应用状态的数据结构,同样可以在这里设置默认的初始状态。
actions:Actions
即是定义提交触发更改信息的描述,常见的例子有从服务端获取数据,在数据获取完成后会调用store.commit()
来调用更改 Store 中的状态。可以在组件中使用dispatch
来发出 Actions
。
mutations
: 调用 mutations
是唯一允许更新应用状态的地方。
getters: Getters
允许组件从 Store
中获取数据,譬如我们可以从 Store
中的 projectList
中筛选出已完成的项目列表
modules: modules
对象允许将单一的 Store
拆分为多个 Store
的同时保存在单一的状态树中。随着应用复杂度的增加,这种拆分能够更好地组织代码
但是vuex
也有缺点就是,vuex
中保存的数据是和网页的生命周期同步的,当执行页面刷新的时候vuex
中所有数据都会消失复位到初始状态,所以不太适合做有分享页面的数据交互(在这种项目中vuex
只适合数据的集中管理,不适合数据的存储,这种情况一般是使用路由传递参数会好一些),适合后台管理系统多一些,后台管理系统一般都是公司内部使用;
6,Vue的路由如何传参?
<router-link :to="{path:‘details‘,query: {id:el.tog_line_id}}">
<router-link :to="{name:‘details‘,params: {id:el.tog_line_id}}”>
然后在组件内部通过$route.params
来读取数据,但是路由传递的参数值是对象的话就不行了会报错,一般都是在传递之前先吧需要传递的数据使用base64
转化一下就不会造成路由报错了
7,Vue和angular的区别?
1.在 API 与设计两方面上 Vue.js
都比 Angular
简单得多,因此你可以快速地掌握它的全部特性并投入开发。
2.Vue.js
是一个更加灵活开放的解决方案。它允许你以希望的方式组织应用程序,而不是任何时候都必须遵循 Angular
制定的规则。它仅仅是一个视图层,所以你可以将它嵌入一个现有页面而不一定要做成一个庞大的单页应用。在配合其他库方面它给了你更大的的空间,但相应,你也需要做更多的架构决策。例如,Vue.js
核心默认不包含路由和 Ajax
功能,并且通常假定你在应用中使用了一个模块构建系统。这可能是最重要的区别。
3.Angular
使用双向绑定,Vue
也支持双向绑定,不过默认为单向绑定,数据从父组件单向传给子组件。在大型应用中使用单向绑定让数据流易于理解。
4.在 Vue.js
中指令和组件分得更清晰。指令只封装 DOM
操作,而组件代表一个自给自足的独立单元 —— 有自己的视图和数据逻辑。在 Angular
中两者有不少相混的地方。
5.Vue.js
有更好的性能,并且非常非常容易优化,因为它不使用脏检查。Angular
,当 watcher
越来越多时会变得越来越慢,因为作用域内的每一次变化,所有 watcher
都要重新计算。并且,如果一些 watcher
触发另一个更新,脏检查循环(digest cycle
)可能要运行多次。 Angular
用户常常要使用深奥的技术,以解决脏检查循环的问题。有时没有简单的办法来优化有大量 watcher
的作用域。Vue.js
则根本没有这个问题,因为它使用基于依赖追踪的观察系统并且异步列队更新,所有的数据变化都是独立地触发,除非它们之间有明确的依赖关系。唯一需要做的优化是在 v-for
上使用 track-by
。
8,Vue和SEO?
vue
主要一个开发框架,通过vue-router
可以实现单页应用的开发,但是单页应用本身就对seo
不友好,现在vue官方给出的解决方案是vue-server-renderer
服务端渲染,但是我觉得对于一个真正适合做成单页应用的项目的话,seo
其实是可以不用考虑的,反正项目本身是需要登录才能进入的,但是像其他一些类似于商城的项目的话,我们可以吧项目分开,像单个的详情页我们没有必要放到单页路由中,可以把她们分出去,毕竟对于商城来说商品才是详情才是需要seo
优化的。或者我们完全没有必要用了vue
就得吧项目做成单页的,我们可以使用一些他的特性,毕竟我觉得vue
给我带来最大的好处就是组件化开发;
9,Vue的优缺点?
优点:
简单:官方文档很清晰,比 Angular
简单易学。
快速:异步批处理方式更新 DOM
。组合:用解耦的、可复用的组件组合你的应用程序。
紧凑:~18kb min+gzip,且无依赖。
强大:表达式 & 无需声明依赖的可推导属性 (computed properties
)。
对模块友好:可以通过 NPM、Bower
或 Duo
安装,不强迫你所有的代码都遵循 Angular
的各种规定,使用场景更加灵活。
缺点:
不兼容ie8,不过总体上觉得vue
对我来说还是非常不错的,能看的懂文档,能上的去手,开发模式也比较好
10,Vue的脚手架有几种?
5种 simple,webpack-simple,vue-cli,browserify,browser-simple
11,指令keep-alive
指令keep-alive
是做组件缓存的,就是把组件缓存起来不会销毁,下次打开这个组件直接显示出来,如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。一般用于有上啦加载的页面,因为如果一个页面有上啦加载的话,用户加载了好几页了都然后点击进入详情,在返回又得重新加载,这个体验很不好,有了keep-alive
后就可以吧这个列表页面保存在内存中避免用户的重复操作,增强用户体验
12.如何让css只在当前组件中起作用
在每一个vue
组件中都可以定义各自的css,js,
如果希望组件内写的css
只对当前组件起作用,只需要在style中写入scoped
,即:
<style scoped></style>
13.Vuejs在变化检测问题
1.检测数组
由于javascript
的限制,vuejs
不能检测到下面数组的变化:
直接索引设置元素,如vm.item[0]={};
修改数据的长度,如vm.item.length。
为了解决问题1,Vuejs
扩展了观察数组,为它添加一个$set()
方法:
// 与 example1.items[0] = ...
相同,但是能触发视图更新
example1.items.$set(0, { childMsg: 'Changed!'})
问题2,需要一个空数组替换items。
除了$set()
,vuejs
也为观察数组添加了$remove()
方法,用于从目标数组中查找并删除元素,在内部调用了splice()
。因此,不必:
var index = this.items.indexOf(item)
if (index !== -1) {
this.items.splice(index, 1)
}
只需:
this.items.$remove(item);
2.检测对象
受ES5
的显示,Vuejs
不能检测到对象属性的添加或删除。因为Vuejs
在初始化时候将属性转化为getter/setter
,所以属性必须在data
对象才能让Vuejs
转换它,才能让它是响应的,例如:
var data = { a: 1 }
var vm = new Vue({
data: data
})
// vm.a
和 data.a
现在是响应的
vm.b = 2
// vm.b
不是响应的
data.b = 2
// data.b
不是响应的
不过,有办法在实例创建之后添加属性并且让它是响应的。对于Vue
实例,可以使用$set(key,value)
实例方法:
vm.$set('b', 2)
// vm.b
和 data.b
现在是响应的
对于普通数据对象,可以使用全局方法Vue.set(object, key, value):
Vue.set(data, 'c', 3)
// vm.c
和 data.c
现在是响应的
有时你想向已有对象上添加一些属性,例如使用 Object.assign()
或 _.extend()
添加属性。但是,添加到对象上的新属性不会触发更新。这时可以创建一个新的对象,包含原对象的属性和新的属性:
// 不使用 Object.assign(this.someObject, { a: 1, b: 2 })
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
14.关于vuejs页面闪烁{{message}}
在vuejs
指令中有v-cloak
,这个指令保持在元素上直到关联实例结束编译。和CSS
规则如[v-cloak]{display:none}
一起用时,这个指令可以隐藏未编译的Mustache
标签直到实例准备完毕。用法如下:
[v-cloak]{
display:none;
}
<div v-cloak>{{message}}</div>
这样
15.组件命名的约定
当注册组件(或者props
)时,可以使用 kebab-case ,camelCase ,或 TitleCase
// 在组件定义中
components: {
// 使用 kebab-case 形式注册
'kebab-cased-component': { /* ... */ },
// register using camelCase
'camelCasedComponent': { /* ... */ },
// register using TitleCase
'TitleCasedComponent': { /* ... */ }
}
在 HTML 模版中,只能使用 kebab-case 形式:
<!-- 在HTML模版中始终使用 kebab-case -->
<kebab-cased-component></kebab-cased-component>
<camel-cased-component></camel-cased-component>
<title-cased-component></title-cased-component>
当使用字符串模式时可以使用 camelCase 、 TitleCase 或者 kebab-case 来引用:
<!-- 在字符串模版中可以用任何你喜欢的方式! -->
<my-component></my-component>
<myComponent></myComponent>
<MyComponent></MyComponent>
16.key的使用
一般情况下,vue
在渲染完成后,如果数据发生变化,只会重新渲染数据,不会重新渲染整个元素,但是有时候我们需要元素被重新渲染,此时就需要使用key
关键字,使用v-bind
绑定key
关键字,可以实现在数据发生变化时候重新渲染整个元素。注:同一父级元素下所有子元素如果都要在数据变化后重新渲染元素,则需要被绑定的key
17,$route
和$router
的区别
$route
是路由信息对象,包含了path,params,query,hash,fullPath,matched,name
这些路由信息参数
而$router
是路由实例对象包含了路由的一些跳转方法,钩子函数等
18,vue路由的钩子函数
官方称为导航守卫可以控制导航的跳转,有beforeEach,afterEach
等,一般用于页面title
的修改,一些需要登录才能调整页面的重定向等功能,beforeEach
主要有3个参数to, from, next
to: Route:
即将要进入的目标 路由对象
from: Route:
当前导航正要离开的路由
next: Function:
一定要调用该方法来 resolve
这个钩子。执行效果依赖 next
方法的调用参数。可以控制网页的跳转
19,watch,computed,methods的区别?
watch
是做单一的数据监听,方法名字必须和需要监听的数据同名,不需要返回值,可以得到数据修改前后修改后的值
computed
和methods
基本相同,都是方法,都是在数据改变的时候如果方法内部有该数据的依赖都是自动执行,
但是它们俩定位不同,computed
是计算属性,而methods
是放的操作方法,
还有就是调用形式不同,计算属性调用不需要加括弧,methods
则需要加()
在一个就是computed
会将计算的值进行缓存,如果方法内部依赖的值没有发生变化调用computed
不管多少次都只是执行一次,其他调用反回的是缓存的值,而methods
则调用多少次就会执行多少次
20,vue中sync的用处?
vue
中sync
其实就是自定义事件的一个语法糖
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
所以他的好处就是简化了自定义事件的写法
21,vue组件怎么划分?
按着页面的框架去划分,将页面中的每一块都可以划分成为一个组件,然后从中提取公共组件,一般都是将组件分为页面组件和公共组件