1.vue2响应式原理/数据绑定的原理
vue会遍历data中所有的属性,并通过object.defindepropty来给每个属性加上getter和setter。
getter和setter使vue能够追踪依赖,在属性被修改时通知变化。
每个组件实例都会有一个自身的watcher实例,他会把组件渲染时用到的属性记录为依赖,当依赖的数据发生变化时,会通知watcher,
从而他关联的组件都会更新。
Vue实现响应式数据的原理主要是通过数据劫持(Data observation)和发布-订阅模式(发布-订阅模式)相结合的方式来实现的。
当我们在Vue中定义一个data对象时,Vue会对这个对象进行遍历,把每个属性都通过Object.defineProperty()方法转换成getter和setter,并注入到Vue实例中的$data中,也就是实现了对属性的改变监控。这样,当我们改变data中的数据时,setter方法会被触发,同时也会通知Watcher对象,Watcher会通知组件,组件会更新视图。
而发布-订阅模式主要是通过Dep类来实现的。在getter中,Vue会实例化一个Dep对象,用于收集Watcher对象,当该属性被修改时,会通知Dep中所有的Watcher对象执行更新操作。而在setter中,当属性被改变时,会通知Dep中所有的Watcher对象执行更新操作。
总结一下,Vue实现响应式数据的原理主要是通过Object.defineProperty()方法实现数据劫持,同时通过Dep类和Watcher对象实现发布-订阅模式,当数据改变时,就会通知相关的Watcher对象,更新组件视图。这种基于数据驱动的设计方式就是Vue的核心思想之一,使得开发者可以更加方便的管理和维护代码。
源码
<script>
let data={
name:'xxx',
address:'xxx'
}
//创建一个监视的实例对象
const obs=new Observer(data);
//vm实例对象
let vm={};
vm._data=data=obs;
function Observer(obj){
//汇总对象中的所有属性形成一个数组
const keys=Object.keys(obj);
keys.forEach((k)=>{
//this指的是Observer
Object.defineProperty(this,k,{
get(){
return obj[k];
},
set(val){
obj[k]=val;
}
})
})
}
</script>
2.vuex、localstorage、sessionstorage的区别
vuex是vue的状态管理,不是持久化存储,可存储多个类型
localstorage是本地存储,持久化存储,清除缓存数据才会消失,只能存储字符串类型。
sessionstorage是会话存储,页面关闭数据会消失,只能存储字符串类型。
3.vue的生命周期
beforeCreate:实例创建之前,此时data和methods都还没有
created:实例创建完成,有了data和methods
beforeMounte:实力挂载之前,页面还没有被渲染。
mounted:实例挂在之后,页面渲染完成。
beforeUpdate:页面更新之前
updated:页面更新完成
beforeDestory:实例销毁之前,可以做一些清除定时器,解绑自定义事件的操作
destoryed:实例销毁完成
如果使用了keep-alive标签则会
activated:在组件第一次渲染时会被调用,之后在每次缓存组件被激活时调用。
deactivated:组件被停用(离开路由)时调用。
4.路由的跳转方法
<route-link to=""></route-link>
this.$router.push({name:'',params:{},})
this.$router.replace()
this.$router.go()
5.v-show和v-if的区别
都是用来控制元素显示与隐藏的指令
v-show是通过控制css的dispaly属性来控制显示和隐藏
v-if是通过对节点的创建与销毁来控制元素的显示与隐藏
如果切换比较频繁,推荐使用v-show来提高性能
如果不频繁则使用v-if
6.hash和history模式的区别
ui展示上:hash地址中会带#,而history没有
hash后面的hash值不会传给服务器,值的变化也不会重新请求服务器
页面刷新,hash模式会刷新当前页面,history模式下如果没有处理的情况下会报404
hash可以兼容低版本的浏览器
7.如何定义动态路由
在router文件夹下的index.js里,给path属性加上:/id
在组件中通过this.$router.params.id获取
8.component和watch的区别
component是计算属性,支持缓存,不支持异步,受依赖属性的影响
watch是监听属性,不支持缓存,支持异步,可以影响依赖属性
9.keep-alive
包裹动态组件时,缓存不活跃的组件实例,保留组件状态,避免重新渲染。
是一个抽象组件,不会渲染成一个dom元素。
有两个钩子函数,activated和deactivated,前者时在mounted之后,初次渲染或者缓存的内容更新时调用,
后者是离开此页面(不会被销毁)时执行。
10.请求接口一般放在那个生命周期函数中?
推荐created:此时data和methods已经准备好,并且可以更快获取服务端数据,减少页面的loading事件,
ssr(服务端渲染server-side rendering)不支持在beforeMounte、mounted里使用。
11.vue的性能优化
尽量减少data里的数据,data里的数据会增加getter和setter,会收集对应的watcher。
v-if和v-for不能连用。
如果需要给v-for遍历的数据绑定事件时,可以使用事件代理。
SPA应用采用keep-alive缓存不活动的组件。
在切换不频繁的情况下使用v-if代替v-show。
使用路由懒加载,异步组件。
使用防抖和节流。
第三方模块按需引入。
图片懒加载,SEO(搜索引擎优化Search Engine Optimization)。
预渲染。
SSR(服务端渲染server-side rendering)。
12.组件传值
父传子:父组件使用v-bind绑定,子组件通过props接收。
子传父:子组件通过绑定事件,用$emit(绑定的事件名,参数),父组件通过自定义事件(或$on)来获取。也可以使用$ref
兄弟或其他组件:全局事件总线$bus、消息订阅与发布inject/provide、vuex、sessionstorage。
13.vue中data为什么必须是一个函数
在组件中,如果使用对象形式,data里面的数据会指向同一个引用地址,一个组件的属性值发生变化,会影响到其他组件。
如果使用函数的形式,每创建一个组件都会返回一个新的对象,使的组件之间的数据互不影响。
14.说一下vuex
是专门为vue.js开发的状态管理模式。
核心:
state:存放共享数据。
mutation:同步操作,唯一可修改state的方法。
action:异步操作,可以进行任何异步操作,可异步提交mutation。
getter:相当于store的计算属性,可对state的数据进行加工处理。
moudle:允许将单一的store拆分成多个store,将store分模块。
总结:在state里初始化状态后,需要显示到组件上,组件通过dispatch向action派发请求,请求修改stste,可以在action里做一些异步操作,
如发送网络请求,之后action通过commit提交到mutation里,将state里的属性修改了之后,就会重新执行render更新组件中的数据。
实现vuex
/**
* 1 实现插件,挂载$store
* 2 实现store
*/
let Vue;
class Store {
constructor(options) {
// state响应式处理
// 外部访问: this.$store.state.***
// 第一种写法
// this.state = new Vue({
// data: options.state
// })
// 第二种写法:防止外界直接接触内部vue实例,防止外部强行变更
this._vm = new Vue({
data: {
$$state: options.state
}
})
this._mutations = options.mutations
this._actions = options.actions
this.getters = {}
options.getters && this.handleGetters(options.getters)
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
}
get state () {
return this._vm._data.$$state
}
set state (val) {
return new Error('Please use replaceState to reset state')
}
handleGetters (getters) {
Object.keys(getters).map(key => {
Object.defineProperty(this.getters, key, {
get: () => getters[key](this.state)
})
})
}
commit (type, payload) {
let entr