1、说一下vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理项目的所有组件的状态。vuex的5个核心
- state 组件状态 我们在项目中一般不把数据存储在主分支上
- mutations 操作state中的数据的方法
- actions 调用mutations的方法 在项目中我们公共数据请求放在actions中了
- getters 对state中的数据做逻辑处理
- modules 对state中的数据分模块 在项目中我们根据功能模块将数据存储到modules模块中,开启了命名空间
vuex的运行机制是
在组件中通过dispatch 调用actions中的方法,在actions中通过commit调用muations中方法,在mutations中可以直接操作state中的数据,只要state中的数据发生改变就会立即响应到组件的视图上
vuex中持久化我们在项目中是通过插件 vuex-persistate实现的。Vuex数据持久化的原理是将Vuex存储在本地存储(localStorage)中,以便在页面刷新或关闭后仍能保留Vuex的状态。具体实现方式是监听Vuex的mutation,每次mutation被触发时,将Vuex的状态存储在本地存储中。在页面初始化时,从本地存储中读取Vuex的状态,恢复之前保存的状态。这样就可以实现Vuex数据的持久化。
vuex的使用方式可以通过映射函数或者挂载到原型上的方法来使用。
vuex在项目中使用是动态路由权限 存储一些用户的公共信息等
2、生命周期
所谓的vue⽣命周期就是vue实例从创建到销毁的整个过程我们称之为vue的⽣命周期,
通过vue的⽣命周期我们可以在不同的阶段进⾏不同的逻辑操作. vue⽣命周期常⽤的钩⼦函数⼀共有8个,分别是创建前后、挂载前后、更新前后以及销毁前后. 分别对应的钩⼦函数为beforeCreate 创建前、 created创建后、beforeMount 挂载前、mounted挂载后、beforeUpdate 更新前、updated更新后、beforeDestory 销毁前、 destoryed销毁后。
⻚⾯⼀开始加载的时候就会触发创建前后和挂载前后的钩⼦函数, ⽽更新的钩⼦函数需要当我们改变data的时候才能触发,⽐如 点击按钮,执⾏⼀个⽅法,在这个⽅式⾥⾯给data⾥⾯属性重新进⾏复制操作,这个时候就会更新的钩⼦函数, 销毁的钩⼦函数必须得当组件进⾏切换的时候就会进⾏销毁.
在项目的开发过程中我们在created和mounted中请求数据或者获取本地数据。如果我们要操作dom只能在mounted中实现(有时 候也存在获取不到dom元素的情况,这个时候我们⼀般⽤$nextTick⽅法来解决),在beforeDestroy的钩子函数中可以移除元素上的事件以及清除定时器等操作。
有父子组件的生命周期函数执行顺序是 :父beforeCreate->父Created->父beforeMounte->子组件的四个钩子->父组件的mounted
使用kepp-alive会增加两个钩子函数 activated 进入缓存页的时候执行 deactivated离开缓存页执行
进入缓存页的时候只有第一次会执行beforeCreate created beforeMount mounted钩子函数
还有一个错误处理钩子 errorCaptured
3、说一下路由导航守卫
所谓的路由守卫就是当我们进⾏⻚⾯跳转的时候会触发的钩⼦函数,我们把它称之为vue路由守卫. vue⼀共给我们提供了三种路由守卫,第⼀种全局路由守卫,第⼆种是组件内路由守卫,第三种路由独享守卫,这个是写在路由⾥⾯. 全局钩子函数beforeEach 路由独享 beforeEnter 组件内 beforeRouteEnter beforeRouteUpdate beforeRouteLeave 这⼏个钩⼦函数⾥⾯都有⼀个回调函数,这个回调函数⾥⾯会有三个参数,分别是to,from,next,分别对应的是要进⼊的路由、离开之前的路由,以及进⼊写⼀个路由
在项⽬中我们经常使⽤路由守卫实现⻚⾯的鉴权. ⽐如:当⽤户登录之后,我们会把后台返回的token以及⽤户信息保存到vuex和本地,当⻚⾯进⾏跳转的时候,我们会在路由守卫⾥⾯获取vuex⾥⾯的token,如果token存在的话,我们则使⽤next让他进⼊要跳转的⻚⾯,如果token不存在的话我们使⽤next⽅法让他回到登录⻚.以上就是我对vue路由守卫的理解
4、vue中的组件通信
- 常用的父子组件通信方式 props emit
父组件传入属性,子组件通过props来接收,在子组件中就可以用this.xxx方式使用
父组件自定义事件挂载要执行的方法,在子组件中通过$emit来触发事件,数据以参数的形式传递
- 任意两个组件通信EventBus
通过$emit来派发事件 通过$on来监听事件
- provide/inject依赖注入
可用于多层嵌套数据传递 缺点传递的数据不是响应的
- vuex
- 本地存储(sessionStorage localStorage)
5、vue2双向数据绑定的原理
vue.js 是采⽤ 数据劫持 结合 发布者-订阅者 模式的⽅式,通过 Object.defineProperty() 来劫持各个属性的 setter , getter ,在数据变动时发布消息给订阅者,触发相应的监听回调。这个时候就可以实现数据的双向绑定。由于defineProperty只能监听某个属性,不能对全对象进行监听。当data上新添加属性的时候无法监听到,所有提供了this.$set()来给data添加属性数据
6、说一下keep-alive
keep-alive是vue内置的⼀个组件,⽽这个组件的作⽤就是能够缓存不活动的组件,我们能够知道,⼀般情况下,组件进⾏切换的时候,默认会进⾏销毁,如果有需求,某个组件切换后不进⾏销毁,⽽是保存之前的状态,⽐如说刚刚填好的表单数据。那么就可以利⽤keep-alive来实现
在搭建 vue 项⽬时,有某些路由组件没必要多次渲染,所以需要将组件在内存中进⾏‘持久化’,此时在router-view上使⽤keep-alive。 keep-alive可以使被包含的路由组件状态维持不变,即便是组件切换了,其内的状态依旧维持在内存之中。在下⼀次显示时,也不会重新渲染。
keep-alive有三个属性 1.include - 字符串或正则表达式。只有名称匹配的组件会被缓存。 2.exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。 3.max-数字最多可以缓存多少组件。
使用keep-alive还会增加两个钩子函数
activated (原因:再次进入到缓存页面mounted就不执行了 缓存的页面接口请求放在activated中)
deactivated(原因:缓存页面离开的时候不会执行beforeDestroy destroyed)
7、v-if和v-show的区别
从效果上来说v-if和v-show都是控制元素的显示与隐藏,然而v-if根据条件创建和删除元素 而v-show是根据条件通过css的dispaly属性显示和隐藏元素。
v-if有更高的切换成本 v-show有更高的渲染成本
在项目中会员页面头像和登录按钮的切换用的v-if(骨架屏 空提示),选项卡使用的是v-show
8、v-if和v-for的优先级哪个高?如果同时使用怎么解决?
v-for的优先级⾼. 因为v-for的时候我们才开始渲染dom元素,这个v-if还⽆法进⾏判断.
v-for和v-if不能同时使⽤,我们可以通过标签,⽐如div或者template标签来进⾏包裹,把v-if写到包裹的标签上⾯(写到v-for外⾯)也可以通过计算属性检索符合条件的数据,然后再渲染计算属性
9、methods、computed和watch的区别
1、methods是⽤来定义⽅法的区域,methods定义的⽅法需要调⽤才能触发. 不具备缓存⾏
2、computed是计算属性,他依赖于属性值的变化,当属性发⽣改变的时候,计算属性⾥⾯定义的⽅法就会触发,computed具有缓存性,依赖属性值的变化⽽变化.
3、watch主要是⽤于监听,不具备被缓存性.依赖于数据变化⽽触发.
在项目中当多个属性影响一个数据的时候我们可以使用computed,当一个属性影响多个数据的时候我们可以选择watch,在watch中我们可以做一些异步操作
watch的属性由deep 深度监听 immediate 理解监听 handler函数
10、说说虚拟dom与diff算法
虚拟dom是一层对真实dom的抽象,以js对象作为基础的数,用对象的属性来描述节点,最终可以通过一些列的操作使这颗树映射到真实环境中。虚拟dom对象至少包括三个属性 标签名(tag) 属性(arg)和子元素对象(children),不同框架对这个三个属性的命名可能有差别。
通过虚拟dom,vue可以对这颗抽象树进行创建节点、删除节点以及修改节点的操作,经过diff算法得出一些需要修改的最小单位,再更新视图,减少dom操作,提高了性能。
就当数据发生改变的时候,新 旧两颗dom数比较用的算法就是diff算法
Vue的dif算法是平级⽐较,不考虑跨级⽐较的情况。内部采⽤深度递归的⽅式+双指针⽅式⽐较
先⽐较两个节点是不是相同节点
相同节点⽐较属性,复⽤⽼节点
先⽐较⼉⼦节点,考虑⽼节点和新节点⼉⼦的情况
优化⽐较:头头、尾尾、头尾、尾头
⽐对查找,进⾏复⽤
11、说一下你对vue的理解 核心特性
vue是一个渐进式js框架,它的特点是组件化、轻量级、虚拟 DOM、响应式、单页面路由、数据与视图分 开、用户体验好。
vue的核心特性是数据驱动视图
12、组件的封装,怎么注册出来,再调用
14、说说路由懒加载
懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。
我们在项目中可以在vue-router配置路由的时候,可以使用import异步加载组件,可以实现按需加载
component: () => import('../views/About.vue')
目的是为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题
15、vue中怎么阻止事件冒泡
使用vue的事件修饰符 .stop
16、声明式导航路由跳转怎么实现的
<router-link to="路径"></router-link>
17、路由传参的方式以及区别
vue中的路由传参有两种方式 query和params
- params传值的参数是路由的一部分,所以调转必须加参数值才能调转 query传参和路由配置没有关系
- 获取方式是不一样的 query this.$route.query.参数名 params是 this.$route.params.参数名
18、vuex做过优化吗
我们在项目中vuex中的数据都是工具功能模块存储的,设置了命名空间。
小问:设置命名空间和不设置命名空间的区别
不设置命名空间只有state分模块,其余的会合并到主分支上
设置命名空间是所有的都分模块
19、vue的核心思想
数据驱动视图
20、在vue中解决低版本浏览器不兼容的问题
通过es6-promise和babel-polyfill的包
21、解决浏览器兼容的问题
给css属性加浏览器前缀
22、vue的路由原理
vue的路由模式⼀共有两种,分别是哈希和history. 他们的区别是hash模式不会包含在http请求当中,并且hash不会重新加载⻚⾯,⽽使⽤history模式的话,如果前端的url和后端发起请求的url不⼀致的话,会报404错误,所以使⽤history模块的话我们需要和后端进⾏配合.
history的原理就是利⽤html5新增的两个特性⽅法,分别是psuhState和replaceState来完成的. 当堆栈的路径发生改变会触发onpopstate()事件来监听路径变化
hash是通过onhashchange()事件来监听hash路径的变化
23、开发时遇到的优化问题 cdn? 性能优化
24、单页面的优点
单页面一套系统就由一个页面来承载,数据的切换是由路由来实现。
优点:
- 由的切换肯定比页面的切换更顺畅 所以spa的切换会好
缺点:
首屏加载慢,但是我们可以通过优化项目来尽可能的提高首屏的加载速度
25、mvvm
MVVM 是把 MVC 的 Controller 和 MVP 的 Presenter 改成了 ViewModel 。
M 数据模型 V是视图 VM 逻辑处理
View 的变化会⾃动更新到 ViewModel , ViewModel 的变化也会⾃动同步到 View 上显示。这种⾃动同步是因为 ViewModel 中的属性实现了 Observer ,当属性变更时都能触发对应的操作
MVVM模式的优点:
1、低耦合: 视图(View)可以独⽴于 Model 变化和修改,⼀个 ViewModel 可以绑定到不同的"View"上,当View变化的时候Model
可以不变,当Model变化的时候View也可以不变。
2、可重⽤性: 你可以把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多 view 重⽤这段视图逻辑。
3、独⽴开发: 开发⼈员可以专注于业务逻辑和数据的开发(ViewModel),设计⼈员可以专注于⻚⾯设计。
4、可测试: 界⾯素来是⽐较难于测试的,⽽现在测试可以针对ViewModel来写。
27、动态路由实现权限列表的流程
在我们的项目中是这么做的
- 先配置一下登录 404等静态路由的页面
- 准备好权限组件需要的组件以及router-view
- 然后用户登录成功后,根据用户的角色拿到响应的权限列表,将用户的权限列表存储到vuex中
- 在router.js的前置路由守卫中将vuex中的权限列表数据通过addRoutes添加到rouer对象中routes中
- 添加完成后为了防止白屏问题,必须通过next({ ...to, replace: true })保证加载完毕才能访问
28、说一下按钮权限
- 登录后根据后台返回的数据,将权限数组信息存储到vuex中,比如['edit','delete']
- 我们封装了一个自定义指令,在调用自定义指令的时候传递当前按钮的功能参数
<button v-premission="delete">删除</button>
- 在自定义指令中,获取获取到参数,然后和vuex的权限数据对比,决定是否需要给按钮设置禁用状态
29、自己封装过常用的组件
弹框 列表 骨架屏
30、印象最深刻的bug
- this指向的问题
- vue2数据更新视图无更新
- 组件样式改变深度穿透
31、vuex与localstorage的区别
vuex是vue提供给我们的状态管理工具,默认的存储到内存中的,做了持久化才会被存储到本地。localStorage是h5新增的API,用来缓存数据的,即使不用vue也能使用。
32、最近工作中遇到的问题
没有对渲染的数据进行判空,导入读取属性的时候js报错,无法解析
改正的:
在渲染的时候加上了v-if判断,不为空的时候在进行渲染
33、从一个页面返回到上一个页面,上一个页面的组件状态还是保持的怎么实现
我们在项目中是通过keep-alive组件包括当前路由的<router-view>,然后通过keep-alive的includes属性来设置要缓存的组件
34、如何判断一个对象是空的
我们在项目中是这么做的
- 可以使用Object.keys()获取到对象的键,返回的是数组,如果数组长度为0那么就是空对象
- 将对象通过JSON.stringify()转换成字符串,再判断是否等于“{}”
- Object.getOwnPropertyNames方法获取对象的属性名,存到数组中,若长度为0,则为空对象
Object.getOwnPropertyNames(obj).names.length==0
- 利用for In
35、vue2和vue3的区别
1、vue2和vue3双向数据绑定原理发生了改变
-
- vue2的双向数据绑定是利用了es5 的一个API Object.definepropert() 对数据进行劫持 结合发布订阅模式来实现的。vue3中使用了es6的proxyAPI对数据进行处理
- 相比与vue2,使用proxy API 优势有:defineProperty只能监听某个属性,不能对全对象进行监听。当data上的属性发生改变的时候无法监听到,所有提供了this.$set()来给data添加属性数据。vue3课可以监听数组,不用再去单独的对数组做特异性操作,vue3可以检测到数组内部数据的变化
2、组合api
-
- vue2使用选项类型api,对比vue3合成型api。旧得选项型api在代码里分割了不同得属性:data,computed,methods等;新得合成型api能让我们使用方法来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁
3、vue3支持碎片化
-
-
- vue2的只有一个根节点 vue3可有有多个根节点
-
4、建立数据不同
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。使用一下三个步骤来建立响应式数据:
1. 从vue引入reactive;
2.使用reactive() 方法来声明数据为响应性数据;
3. 使用setup()方法来返回我们得响应性数据,从而template可以获取这些响应性数据。
5、生命周期函数不同
6、父子传参的不同
-
-
- setup()函数接收两个参数:props、context
- 父传子,用props接受数据,子传父用事件 Emitting Events。在vue2中,会调用this$emit然后传入事件名和对象;在vue3中得setup()中得第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了
-
36、$router和$route的区别
$route是一个跳转的路由对象,每一个路由都会有一个$route对象,是一个局部的对象,可以获取对应的name,path,params,query等
$router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。
37、vue的项目搭建
我们公司是用vue-cli搭建的项目,在新建项目的过程中我大致的做了这些工作
- 梳理静态资源目录
- 配置vuex的持久化以及模块的设置
- 封装axios的request请求文件,设置请求拦截和响应拦截为以后封装api接口做准备
- 设置路由目录等等
38、$nextTick函数
- nextTick机制
Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所 有数据变化完成之后,再统一进行更新。
- 为什么会有nextTick机制
举个例子
{{num}}for(let i=0; i<100000; i++){ num = i}
如果没有 nextTick 更新机制,那么 num 每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图),有了nextTick机制,只需要更新一次,所以nextTick本质是一种优化策略
- 使用场景
- 如果想要在修改数据后立刻得到更新后的DOM结构,可以使用$nextTick函数
- 在生命周期mounted渲染的时候,不能百分百保证所有的子组件都能够被渲染,因此我们可以在mounted里面使用 this.$nextTick,这样就能保证所有的子组件都能被渲染到
39、vue-router的参数传递以及区别
- params传值的参数是路由的一部分,所以调转必须加参数值才能调转 query传参和路由配置没有关系
- 获取方式是不一样的 query this.$route.query.参数名 params是 this.$route.params.参数名
40、如果后端不通过调接口,直接给前端传数据用什么方法
websocket
41、element-ui 用过吗;都用了什么组件;form表单校验做过吗:route 邮箱的正则是什么 自己网上查的
42、为什么用element这个框架,你觉得特点是什么,对你的最大帮助
43、封装过自定义指令吗
我们可以使用Vue.directive()来注册全局自定义指令,可以在选项api中通过directives来注册局部的自定义指令。在定义指令的时候有5个钩子函数:
- bind: 只调用一次,指令第一次绑定到元素时调用 可以写元素样式
- inserted: 被绑定元素插入父节点时调用 可以操作dom
- update: 被绑定元素所在的模板更新时调用
- componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
- unbind: 只调用一次, 指令与元素解绑时调用。
每个钩子函数都有两个参数 el binding el是原生dom对象 binding是当前指令的参数对象
我们在项目中使用场景可以实现输入框的防抖 图片懒加载 权限校验 页面水印等应用场景
下面我说一个防抖的自定义指令吧
//防抖的自定义指令
Vue.directive("throttle",{
bind:(el,binding)=>{
let throttleTime=binding.value;//设置防抖的时间
//如果不设置防抖时间 则默认2s
if(!throttleTime){
throttleTime=2000;
}
let cb;
el.addEventListener("click",event=>{
if(!cb){
//第一次执行
cb=setTimeout(()=>{
cb=null
},throttleTime)
}else{
//如果不是第一次点击的话取消当前事件
event&&event.stopImmediatePropagation()
}
},true)
}
})
//在按钮上的应用
<button @click="test" v-throttle>点击</button>
44、vue的事件修饰符
.lazy 将文本框的input事件转换为change事件
.trim 去除文本框空格
.number 将文本框数据类型转为
45、了解过vue3吗,说说与v2的双向绑定的方式有什么不同object.defineProperty有什么弊端
-
- vue2的双向数据绑定是利用了es5 的一个API Object.definepropert() 对数据进行劫持 结合发布订阅模式来实现的。vue3中使用了es6的proxyAPI对数据进行处理
- 相比与vue2,使用proxy API 优势有:defineProperty只能监听某个属性,不能对全对象进行监听。当data上的属性发生改变的时候无法监听到,所有提供了this.$set()来给data添加属性数据。vue3课可以监听数组,不用再去单独的对数组做特异性操作,vue3可以检测到数组内部数据的变化
46、如果说页面中又有文字和图片,怎么做
47、页面滚动,图片大,怎么做不影响用户体验
图片压缩
49、vue中有静态的如图片文件,怎么存放的
静态资源可以通过两种方式进行处理:
- 在 JavaScript 被导入或在 template/CSS 中通过相对路径被引用。这类引用会被 webpack 处理。
- 放置在 public 目录下或通过绝对路径被引用。这类资源将会直接被拷贝,而不会经过 webpack 的处理
1、assets放可能会变动的文件 assets目录中的文件会被webpack处理解析为模块依赖,只支持相对路径形式。
2、简单来说就是就是public放别人家js文件(也就是不会变动),assets放自己写的js、css文件(需要改动的文件)
50、axios里的 .then 和 .catch是怎么用的,捕获到失败怎么去处理
52、一个父组件有两个子组件,这两个子组件怎么传值
可以使用兄弟组件通信,也可以用父子通信或者vuex 本地存储等
53、你用的路由模式是
我们用的hash
54、props可以接受函数吗
可以
55、用什么方法搭建的vue项目
vue-cli搭建的项目
56、data中的数据更新,视图不更新怎么解决
data发⽣变化,视图不更新,因为Vue实例中的数据是响应式的⽽我们新增的属性并不是响应式的,由于受现在JavaScript的限制,Vue⽆法检测到属性的新增或删除。所以有时⽆法实时的更新到视图上。
所以我在项⽬中遇到这类问题的时候⼀般是通过this. $set方法去解决this.$set⽅法⼀共有三个参数,分别是⽬前属性,新增属性,新增的值.以上就是我对视图不更新的理解
57、说一下vue中常用的内部指令
常用的内部指令:v-on、v-bind、v-if、v-show、v-for、v-html、v-text;
v-if和v-show的区别:v-show是从元素的display:none来控制dom的显示与隐藏,而v-if是直接进行的dom节点的添加与移除,比较消耗性能;
v-if和v-for为什么不能放在同一个标签:v-for比v-if优先级高,先执行v-for遍历一下dom节点,再用v-if移去不需要的dom,进行了不必要的dom操作,造成重绘与回流。
58、为什么会用vue替换之前的jq
因为jq主要用的是对dom的操作,dom操作频繁所以比较消耗性能
用vue有虚拟dom,就不用频繁的操作dom;并且vue组件化开发,提高效率;有丰富的API;双向数据绑定;单向数据流;可以结合第三方ui库
59、做过滚动加载吗?在element中怎么实现的
做过 小兔鲜的项目中自己封装过 element-ui有个组件可以找一下哦
60、template模板与rander函数
都是去渲染dom的;后有个返回值,反到html里
61、刷新token,token的有效期,从什么时候开始
62、spa首屏加载速度慢怎么解决
首先首屏加载时间指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定全部渲染完成,但是需要展示当前视口的内容。所以首屏加载是用户体验中最重要的内容。
常用的首屏优化方式:
- 减少入口文件体积
最常用的手段就是路由懒加载 把不同路由对应的组件分割成不同的代码块,待路由被请求的时候单独的打包路由,使得入口文件变小,加载速度大大增加
component: () => import('../views/About.vue')
- 静态资源本地缓存
采用http缓存,设置Cache-Control,Last-Modifid,Etag等响应头
采用Service Worker 离线缓存
- ui框架的按需加载
- 图片资源压缩
图片资源虽然不在编码过程中,但是对页面性能影响最大的因素,对所有的图片资源,可以适当的压缩。对于页面上用到的icon我们可以使用在线字体图标或者雪碧图,将小图合并到一张大图上,用于减轻http请求压力
- 组件的重复打包
在webpack的config文件中,修改CommonChunkPlugin的配置 minChunks:3,表示会把使用3次及以上的包抽离出来,放进公共的依赖文件,避免重复加载组件。
- 开启gzip压缩
- 使用SSR
SSR(Server side)也是服务端渲染,组件或者页面通过服务器生成html字符串,再发送到浏览器从头搭建一个服务端渲染是很复杂的,vue建议使用Nuex.js来实现服务端的渲染
63、说一下混入?什么时候会用到混入
mixin(混入)在我们日常开发中,会遇到不同组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立,可以用mixin提取出来。
当组件存在和mixin对象相同的选项时,组件中的选项会覆盖mixin中的数据。但是如果选项为生命周期钩子的时候会合并成一个数组,先执行mixin 的钩子再执行组件中的钩子。data中的数据会合并。