目录
2.使用 Object.defindproperty() 来劫持数据有什么缺点
9. vue data中的属性发生改变,视图中的数据会立即同步执行发生渲染吗?
22. vue-router 和 loaction.href的区别
35. qs的 stringify 和 JSON 的 stringify 的区别
1.双向数据绑定的原理
(1)vue采用数据劫持结合发布者-订阅者模式的方式,通过Object.defindproperty()劫持各个数据的setter、getter,在数据发生变化时会发送消息给订阅者,触发相应的监听回调
(2) Object.defineProperty
方法接受三个参数:
1.obj
:要在其上定义属性的对象。
2.prop
:要定义或修改的属性的名称。
3.descriptor
:将被定义或修改属性的描述符。
2.使用 Object.defindproperty() 来劫持数据有什么缺点
(1)对于数组或者对象而言,修改其属性是该方法无法拦截的,不能触发组件渲染。只不过vue内部通过重写函数的方法来解决这一缺陷。在vue3.0中采用了proxy()方法对对象进行代理,该方法能完美监听到数据的任何改变。但是有唯一的缺陷就是兼容性、因为proxy是ES6的语法。
3.computed和watch的区别
(1)computed:1. 支持缓存,只有所依赖的数据发生改变时才会触发
2.不支持异步,computed有异步得到的数据无法监听
3.默认走缓存,数据依赖是data中的值或者父组件传来的值
(2)watch:1. 不支持缓存(数据发生变化就会触发)
2. 支持异步
3. 传入的参数有2个,第一个是新的值、第二个是旧的值
4. 监听的数据是基于data声明或者父组件传过来的值
4.computed和methods
(1)computed:只有基于它们的依赖发生改变才会触发计算属性
(2)methods:调用时总会执行
5. v-if 和 v-show的区别
v-if 是动态的向DOM树增加和删除DOM元素,在切换的过程中有编译/卸载的过程并且具有更高的切换消耗,适用于一些不经常改变状态的场景。
v-show是通过设置DOM元素的css样式控制显隐,对于切换时性能的消耗低于v-if,仅在初始时进行渲染,适用于切换频繁的场景
6.为什么vue中的data是函数
(1)因为对象是引用类型,多个实例引用同一个对象时,只要有一个对其进行修改其他实例中的数据也会改变
(2)在vue中,大多数都要复用组件,这样每个组件都会拥有自己的数据,组件间就不会相互干扰
8. 单页面应用和多页面应用的区别
(1)单页面应用:指只有一个主页面的应用,一开始只需要加载一次js、css等相关资源。所有内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅仅刷新局部资源
(2)多页面应用:指有多个独立页面的应用,每个页面必须重复加载js、css等相关资源。多页应用跳转,需要整页资源刷新
9. vue data中的属性发生改变,视图中的数据会立即同步执行发生渲染吗?
(1)不会立即同步执行发生渲染。vue实现响应式并不是数据一发生变化DOM就会立即改变,而是会开启一个队列。vue修改DOM是异步操作。而相同的watcher被改变,只会被推入一次到队列中,这样可以减少计算和DOM的操作。在下一次的事件循环tick中vue会重新刷新队列
(2)使用vue.nextTick()这个方法,在下次的DOM更新结束后执行延迟回调,修改数据后使用此方法可以获取到更新后的数据
10. assets和static的区别
(1)两者都是项目中存放静态资源的文件
(2)不同点:在项目打包时,使用npm run build assets文件将会被打包放置在static文件一起跟着index.html上传到服务器。而static文件则不会被打包,而是跟着一起上传(有利于提高打包效率)
11.delete和vue.delete删除数组的区别
(1) delete是将被删除的元素变为 empty/undefined,其他元素的键值依然不变
(2)vue.delete是直接将数组对象里的键值删除,改变了数组的键值
12. 对SSR的理解
(1)SSR就是服务端渲染,是vue将在客户端的标签渲染成HTML界面放到服务端上去完成,完成后在将HTML界面返回给客户端
(2)优点: 1. 更好的SEO 2. 首页加载更高效快速
(3)缺点: 1. 对开发不友好,服务器端渲染只支持beforeCreate和created两个钩子。
2. 更多的服务端负载
13. vue项目优化的方法
(1)减少data中的数据 、避免v-if和v-for一起使用、尽量使用v-if代替v-show、对于SPA页面使用keep-alive进行组件缓存、路由懒加载、使用图片懒加载、防抖节流、第三方插件按需引入、雪碧图、压缩CSS样式和JS脚本、减少DOM的操作
(2)使用cdn加载第三方模块
14. mixin和mixins
(1)mixin
用于全局混入,会影响到每个组件实例,通常插件都是这样做初始化的。
(2)mixins 是扩展组件的方式,通常各个组件内有相同的业务逻辑都可以抽离出来放在mixins里、但是mixins里的钩子函数会比组件里的钩子函数先执行
15. created和mounted的区别
(1)created:是在渲染成html页面前使用,通常是要初始化一些数据,在渲染成视图
(2)mounted:是在渲染成html页面后使用,通常是在界面渲染完成后需要对一些DOM进行操作
16. keep-alive的生命周期
(1) keep-alive是vue对组件的一种缓存方式,在组件切换的时候保存组件的状态,避免多次渲染。使用keep-alive就会多出两个生命钩子deactivated、activated而beforeDestroy 和 destroyed这两个钩子就不会再被触发,因为没有真正意义上的销毁。当组件被换掉时,会被缓存到内存中、触发 deactivated 生命周期;当组件被切回来时,再去缓存里找这个组件、触发 activated钩子函数
(2)keep-alive的三个属性:include、exclude、max(数字:最大缓存数)
17.组件传值
(1)$emit \ $on (eventBus事件总线)
(2)props \ $emit
(3)依赖注入(project \ inject)
(4)ref \ $refs
(5)$parent \ $children
(6)$attr \ $listeners
18. 路由加载
(1)非加载
import List from '@/components/list.vue'
const router = new VueRouter({
routes: [
{ path: '/list', component: List }
]
})
(2)使用箭头函数+import动态加载
const List = () => import('@/components/list.vue')
const router = new VueRouter({
routes: [
{ path: '/list', component: List }
]
})
(3)使用箭头函数+require动态加载
const router = new Router({
routes: [
{
path: '/list',
component: resolve => require(['@/components/list'], resolve)
}
]
})
(4)使用webpack的require.ensure技术,也可以实现按需加载。 这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
// r就是resolve
const List = r => require.ensure([], () => r(require('@/components/list')), 'list');
// 路由也是正常的写法 这种是官方推荐的写的 按模块划分懒加载
const router = new Router({
routes: [
{
path: '/list',
component: List,
name: 'list'
}
]
}))
19. 如何监听hash的变化
(1)监听$route的变化
// 监听,当路由发生变化的时候执行
watch: {
$route: {
handler: function(val, oldVal){
console.log(val);
},
// 深度观察监听
deep: true
}
},
(2)使用window.location.hash读取#值
20. $route和$router的区别
(1)$route是获取路由信息对象,包括path,params,hash,query,fullPath,matched,name 等路由信息参数
(2)$router是路由的实例对象,包括子路由的跳转方式和生命钩子
21. 如何定义动态路由,如何获取传过来的参数
(1)params方式:
格式:/router/:id
传递方式:在path后面跟上特定的值
效果:/router/123
(2)路由定义:
//在APP.vue中
<router-link :to="'/user/'+userId" replace>用户</router-link>
//在index.js
{
path: '/user/:userid',
component: User,
},
(3)路由跳转
// 方法1:
<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link
// 方法2:
this.$router.push({name:'users',params:{uname:wade}})
// 方法3:
this.$router.push('/user/' + wade)
(4)获取参数:this.$route.params
(1)query的方式
格式:/router
对象中使用query的key作为参数传递
结果:/router?name=123
(2)路由定义
//方式1:直接在router-link 标签上以对象的形式
<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">档案</router-link>
// 方式2:写成按钮以点击事件形式
<button @click='profileClick'>我的</button>
profileClick(){
this.$router.push({
path: "/profile",
query: {
name: "kobi",
age: "28",
height: 198
}
});
}
(3)跳转方法
// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按钮</router-link>
// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})
// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按钮</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})
// 方法5:
this.$router.push('/user?uname=' + jsmes)
(4)获取参数:this.$route.query
22. vue-router 和 loaction.href的区别
(1)使用后者进行跳转简单方便,但是会刷新界面
(2)使用前者进行跳转不会刷新界面,会根据diff算法来按需加载减少DOM的操作
23.params 和 query的区别
(1)query需要path来引入,而params需要name来引入,不过两者查询参数的方式差不多
(2)query类似AJAX的get传值会在url上显示、params类似AJAX的post传值不会在url上显示
(3)query在刷新界面时参数不会丢失,而params会丢失
24. vuex和localStorage的区别
(1)vuex里的数据是存在内存中,localStorage的数据是以文本形式存在本地且只能存储字符串类型的需要用JSON.parse/JSON.stringify
(2)vuex是vue.js提出来的一个可以管理项目状态的仓库,localStorage是本地存储在浏览器中
(3)vuex中可以存储的数据大小比localStorage的大得多
(4)vuex只要刷新界面数据就会丢失、而localStorage不会
25. 为什么不推荐使用下标作为key
(1)因为数组不管如何颠倒,下标始终是0.1.2.3这样排列下去。这样不仅会导致数据的错乱,也会导致vue多次复用旧的节点导致一些不必要的工作
26.vue-router实现的原理
概念:通过改变 URL,在不重新请求页面的情况下,更新页面视图。
路由模式有2种(hash和history):
hash模式在url中含有#符号,但是仅有#符号前的内容会被包含在请求中#后的不论怎么写都不会返回404
history模式中前端url地址必须和后端的一致否则返回404,history含有push和replace方法
27.vue中的插槽
vue插槽有3种:默认插槽,具名插槽,作用域插槽
28.sync的作用
该修饰符的作用是可以使子组件向父组件传值
29.vue中scoped
scoped是阻止穿透(防止全局污染),在使用组件库时会有一个date对其相应的属性做唯一标识。要想修改其样式有2种方法:(1)可以重写一个style (2)使用/deep/、>>>、::deep三者中的一个
30.vue中的自定义指令
vue中的自定义指令:全局指令(vue.directive)、局部指令(directive)
其可以接受参数(id,定义对象),其中的钩子函数:
1. bind:
在指令第一次绑定到元素时调用(在该环节中是获取不到父节点的,父节点是null)。在这里可以进行一次性的初始化设置。
2. inserted:
被绑定元素插入父节点时调用(在该环节中是可以获取到父节点的)
3. componentUpdated:
指令所在的组件以及子组件全部更新后调用
4.unbind:
指令和元素解绑的时候调用一次
31.vue中的watch的deep和immediate
deep:其值为 true/false,确认是否深度监听(深度监听可以监听对象属性和数组的变化)
immediate:其值为 true/false,确认是否以当前的初始值执行 handler 函数。
immediate 设为 true 后,则监听的这个属性会立即输出,也就是说一刷新页面就会在控制台输出,当然此时页面上的数据我们还没来得及手动让其发生变化,所以在控制台输出的newValue为我们在代码中默认设置的值,oldValue输出为“undefined”。
32.父子组件之间生命周期加载顺序
界面渲染时:beforecreated(父) =》created(父) =》beforemounted(父)=》beforecreated(子)=》created(子)=》beforemounted(子)=》mounted(子)=》mounted(父)
数据更新时:beforeUpdate(父)=》beforeUpdate(子)=》Update(子)=》Update(父)
界面卸载时:同上
33.vue的两个核心
1.双向数据绑定 2.组件系统
34.MVC、MVP、MVVM的区别
MVC:模型层、视图层、控制层(1.V->C->M->V view接受指令 2.C->M->V control接受指令)。优点:耦合性低、重用性高、可维护性高。
MVP:模型层、视图层、逻辑层(V和M之间不通信、通过P来传递、P将V、M完全分离)
与MVC的区别:V不直接使用M而是通过P来通信
优点:模型与视图分离,修改视图可不影响模型、更高效的使用模型
MVVM:与MVC模式类似、目的是分离V和M。优点:低耦合、可重用性
35. qs的 stringify 和 JSON 的 stringify 的区别
qs.stringify是将 对象序列化成url 的形式并以 & 进行拼接,qs.parse 是将url 解析成对象。当给qs.stringify传字符串时,得到的结果是空。给qs.parse传字符串时会解析成对象并以字符串作为键、值为空。
JSON.stringify 将对象转成JSON格式、JSON.parse 将JSON格式的字符串转成对象
36. vue中从a界面跳转到b界面经历的生命周期
1、 B.created()
2、 B.beforeMount()
3、 A.beforeDestroy()
4、 A.destroyed()
5、 B.mounted()
37. vue中常用修饰符
一、事件修饰符
1、.stop:阻止事件冒泡
2、.prevent:提交事件不再重新加载页面,可以用来阻止表单提交的默认行为
3、.once:点击事件只会触发一次
4、.native:使用时将被当成原生HTML标签看待
二、按键修饰符
1、@keyup:键盘抬起
2、@keydown:键盘按下
3、按键码:在键盘修饰符后面添加.xxx,用于监听按了哪个键
常用按键码:.enter,.tab,.delete,.esc,.up,.down,.space等。
三、表单修饰符
1、.lazy:在表单输入时不会马上显示在页面,而是等输入完成失去焦点时才会显示;
2、.trim:过滤表单输入时两边的空格;
3、.number:限制输入数字或将输入的数据转为数字
38. vue的动态路由
1. 在路由表中配置meta属性,扩展权限相关字段,在路由守卫导航里判断这个权限标识,实现路由的动态增加和跳转(在router.BeforeEach中使用router.addRoutes来增加对应的路由)
2. 根据登录账号,返回用户角色权限
3. 前端在根据角色,跟路由表中的meta.role中匹配
4. 把匹配搭配的路由形成可访问的路由
39. vue中的diff算法
vue中的diff算法是用来比较新旧虚拟DOM的差异的,并找出最小DOM的操作方式来更新DOM算法。这样做是为了减少不必要的DOM操作,减缓界面的渲染。
diff算法就是虚拟DOM比对时用的,返回一个patch对象,这个对象的作用就是存储新旧两个节点不同的地方,最后用patch中记录的信息更新真实的DOM
步骤如下:
1. 当新旧节点是同一节点类型时,比较它们的属性,对根节点进行更新
2. 新节点如果是文本节点,并且和旧节点不同,则直接替换旧节点
3. 如新节点是注释节点,则根据是否相同进行相应的操作
4. 当旧节点不存在,新节点存在时,执行插入操作。
5. 当旧节点存在,新节点不存在时,执行删除操作。
6. 当节点的key相同时可复用节点
7. 对子节点进行递归比较
40. vue的v-model原理
v-model本质上是语法糖,其实现原理包含两个步骤: 1. 通过v-bind绑定value属性。2. 通过v-on给当前元素绑定一个input事件
41. vue中hash和history的区别
1. hash模式下url上有#号,history模式没有
2. 在做回车刷新界面的时候hash会加载对应的界面,history会返回404
3. hash模式支持旧版本的浏览器,history不支持,因为是H5新增的API
4. hash不会重新加载界面,单页面应用必备
5. history有历史记录,H5新增了pushstate和replacestate()去修改历史记录,并不会立刻发送请求(可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history 模式下,前端的 URL必须和实际向后端发起请求的URL一致,否则会报404错误)
6. history需要后台配置
42. vuex在刷新界面的时候数据会丢失的处理方法
1. 把数据存储在浏览器本地缓存中
2. 在刷新界面的时候重新请求接口
监听浏览器的刷新事件,在刷新前把数据保存到sessionstorage里,刷新后请求数据,请求到了用vuex,如果没有那就用sessionstorage里的数据
43. vue的首屏优化
1. 使用路由懒加载
2. 非首屏组件使用异步组件
3. 首屏不重要的组件异步加载
4. 静态资源放CDN上
5. 减少首屏上css,js等文件资源的大小
6. 使用服务端渲染
7. 尽量减少DOM的数量的层级
8. 使用精灵图,做一些loading
9. 开启Gzip压缩,图片懒加载
44. 为什么使用MVVM,MVVM是什么?
MVVM(Model-View-ViewModel)是一种软件架构设计模式,它是一种简化用户界面的事件驱动编程方式。
在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者。ViewModel是连接View和Model的中间件。
- ViewModel能够观察到数据的变化,并对视图对应的内容进行更新。
- ViewModel能够监听到视图的变化,并能够通知数据发生变化
为什么要使用MVVM:
低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候,View也可以不变。
可复用:可以把一些视图逻辑放到一个ViewModel里面,让很多View重用这段视图逻辑。
独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。