1.写一下对MVVM思想的理解
Model(模型):负责从数据库中取数据
View(视图):负责展示数据的地方
VM:也就是View-Model,做了两件事达到了数据的双向绑定 一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。
思想:实现了 View 和 Model 的自动同步,也就是当 Model 的属性改变时,我们不用再自己手动操作 Dom 元素,来改变 View 的显示,而是改变属性后该属性对应 View 层显示会自动改变(对应Vue数据驱动的思想)
2.在vue组件中,data为什么是一个返回对象的函数?
如果data是对象的话,由于对象是引用类型,组件被复用的话,就会创建多个实例。本质上,这些实例用的都是同一个构造函数。这样就会影响到所有的实例,所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。
3.v-if与v-show的区别是什么
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
4.组件中data,computed和watch的区别
在Vue组件中,data、computed和watch都是用来处理数据的,它们的主要区别如下:
data:组件内部的数据源,可以用来存储和处理组件内部的数据。通过在组件中定义一个data属性来声明一个数据源。
computed:计算属性,用于计算和处理需要从data中获取的数据,提供一种简洁的方式来处理模板中的复杂逻辑。computed属性具有缓存机制,只有在它的依赖项发生变化时才会重新计算。
watch:用于观察和响应数据的变化,当被观察的数据发生变化时,watch中的回调函数会被调用。可以用watch来处理一些需要在数据变化时立即执行的操作,例如异步操作等。
总的来说,data用于存储组件内部的数据,computed用于计算和处理需要从data中获取的数据,而watch用于处理数据的变化。
如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化。
5.在vue开发时,改变数组或者对象的数据,什么情况页面视图没有更新?如何解决?
Vue 不能检测以下数组的变动:
1.当你利用索引直接设置一个数组项时
2.当你修改数组的长度时
3.对于对象:
Vue 不能检测到给已有对象添加的新属性:例如:vm.obj.age= 18
解决方案:对于数组可以使用 Vue.set() 或者 vm.$set()或者splice
对于对象:Vue.set() 或者 vm.$set()或者splice或者 Object.assign()
6.组件之间通信的方式有哪些,是如何通信的
1. 父传子 通过在父组件自定义属性,在子组件通过props接收
2. 子改父或者子传父 在父组件中通过自定义事件传递方法,在子组件中通过$emit接收自定义事件
<children @ eventChange=”change”></children>
this.$emit(‘eventChange’,100)
3. 兄弟之间通信 通过一个事件总线(eventBus 其实是一个空实例),在A组件中通过$on绑定自定义事件 在B组件中通过$emit接收组件
4.通过$parent /$children/$refs $parent指的是父组件实例 $children/$refs是子组件实例
5. $attrs & $listeners
$attrs获取父组件中不被props接收的自定义属性 并且可以通过 v-bind="$attrs" 传入内部组件
$listeners获取父组件中的自定义事件
6.provide & inject 祖先和后代之间的通信
Provide的值可以是对象或者是返回对象的函数
7.Vue的v-model双向绑定原理是什么
v-model本质就是一个语法糖,可以看成是value + input方法的语法糖。 可以通过model属性的prop和event属性来进行自定义。原生的v-model,会根据标签的不同生成不同的事件和属性
text 和 textarea 元素使用 value 属性和 input 事件
checkbox 和 radio 使用 checked 属性和 change 事件
select 字段将 value 作为 prop 并将 change 作为事件
可以将v-model进行如下改写:
<input v-model="sth" />
等同于
<input :value="sth" @input="sth = $event.target.value" />
这个语法糖必须是固定的,也就是说属性必须为value,方法名必须为:input。
8.<keep-alive></keep-alive>的作用是什么?什么场景使用?常用属性?生命周期?
keep-alive可以实现组件缓存,当组件切换时,主要用于保留组件状态或避免重新渲染
使用场景:比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
常用的两个属性include/exclude,允许组件有条件的进行缓存
actived 在keep-alive中使用,缓存组件激活
deactived 在keep-alive中使用,缓存组件不激活
9.写出vue中的所有的生命周期函数,分别有什么作用
beforecreate:实例已经初始化,但不能获取DOM节点。(没有data,没有el)
created:实例已经创建,仍然不能获取DOM节点。(有data,没有el)
载入阶段:
beforemount:模板编译完成,但还没挂载到界面上。(有data,有el)
mounted:编译好的模板已挂载到页面中(数据和DOM都已经渲染出来)。
更新阶段:
beforeupdate:数据发生变化立即调用,此时data中数据是最新的,但页面上数据仍然是旧的(检测到数据更新时,但DOM更新前执行)。
updated:更新结束后执行,此时data中的值和页面上的值都是最新的。
销毁阶段:
beforedestroy:当要销毁vue实例时,在销毁之前执行。
destroy:在销毁vue实例时执行。
actived 在keep-alive中使用,缓存组件激活
deactived 在keep-alive中使用,缓存组件不激活
10.写出vue路由中的导航守卫以及导航守卫回调函数中三个参数的作用
全局守卫:beforeEach,afterEach
局部守卫:
beforeRouteEnter:因为当守卫执行前,组件实例还没被创建,不能获取组件实例的this
beforeRouteUpdate: 在当前路由改变,但是该组件被复用时调用,可以访问组件实例 this
beforeRouteLeave:导航离开该组件的对应路由时调用,可以访问组件实例 this
每个守卫方法接收三个参数:
to:目标路由对象
from:准备要离开的路由
next():进行管道中的下一个钩子。可传递参数有布尔值false,直接写路径'/'或{path:'/'},回调函数
注意:后置钩子函数afterEach不会接受next函数也不会改变导航本身。
11.写出$route与$router的区别
$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等
12.vue-router路由传参有哪些方法,如何获取路由参数。
params⽅法传参的时候,要在路由后⾯加参数名占位;并且传参的时候,参数名要跟路由后⾯设置的参数名对应。
/user/:id这个路由匹配/user/111, /user/222这⾥的 id就是 params
query⽅法,就没有这种限制,直接在跳转⾥⾯⽤就可以。
query传参和params传参的区别
1)query 传参配置的是 path,而 params 传参配置的是name,且在 params中配置 path 无效
2)query传递的参数会显示在地址栏中,而params传参不会
3)query传参刷新页面数据不会消失,而params传参刷新页面数据回消失
4)params可以使用动态传参,动态传参的数据会显示在地址栏中,且刷新页面不会消失,因此可以使用动态params传参,根据动态传递参数在传递页面获取数据,以防页面刷新数据消失
13.vuex是什么?怎么使用?哪种功能场景使用它
vuex 就是一个仓库,仓库里放了很多对象。
其中 state 存放的是数据状态,不可以直接修改里面的数据。
getters类似vue的计算属性,主要用来过滤一些数据。
mutations:存放的是动态修改Vuex的state中保存的数据状态的方法。
actions:保存的触发mutations中方法的方法,可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。
一般什么样的数据会放在 State 中呢?
目前主要有两种数据会使用 vuex 进行管理: 1、组件之间全局共享的数据 2、通过后端异步请求的数据 比如做加入购物车、登录状态等都可以使用Vuex来管理数据状态
怎么使用Vuex? 在main.js引入store,注入。新建了一个目录store,… export
场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车
14.vue中hash模式和history模式的区别
在最明显的显示上:hash模式的URL中会夹杂着#号,而history没有。
Vue底层对它们的实现方式不同:
hash模式是依靠onhashchange事件(监听location.hash的改变)
history模式是主要是依靠的HTML5 history中新增的两个方法,pushState()可以改变url地址且不会发送请求,replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改。
当真正需要通过URL向后端发送HTTP请求的时候,比如常见的用户手动输入URL后回车,或者是刷新(重启)浏览器,这时候history模式需要后端的支持。因为history模式下,前端的URL必须和实际向后端发送请求的URL一致,例如有一个URL是带有路径path的(例如www.libai.wang/blogs/id),如果后端没有对这个路径做处理的话,就会返回404错误。所以需要后端增加一个覆盖所有情况的候选资源,一般会配合前端给出的一个404页面。
15.说一下对路由懒加载的理解以及路由表中时如何使用路由懒加载的,举例说明
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:
将import UserDetails from './views/UserDetails.vue'
替换成
const UserDetails = () => import('./views/UserDetails.vue')
const router = createRouter({
routes: [{ path: '/users/:id', component: UserDetails }],
})
16. watch有哪些属性,分别有什么用?
// 简单写法
watch:{
// 函数接受两个参数,用于监视指定数据变化
// -newValue:数据变化后的结果
// -oldValue:数据变化前的结果
sum(newValue, oldValue){
console.log('求和的值变化了',"变化后的值是"+newValue, '变化前的值是'+oldValue);
}
},
//完整写法
watch:{
sum:{
// 深度监视,因为watch默认只是浅层监视
depp:true,
// 在初始化完成之后就触发监听
immediate:true,
// 监视属性的回调
handler(newValue, oldValue){
console.log('求和的值变化了',"变化后的值是"+newValue, '变化前的值是'+oldValue);
}
}
},
17.写出vue插槽有哪些,如何使用
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。通俗的说是:slot 是在父组建控制了子组件显示或隐藏相关内容。
插槽又分为三种,1.普通插槽 2.具命插槽 3.作用域插槽
1.匿名插槽 : 父组件传递 一个html结构 给子组件
(1)子组件: <slot> 插槽默认内容 </slot>
(2)父组件: <子组件> html结构 </子组件>
2.具名插槽 : 父组件传递 多个html结构 给子组件
(1)子组件: 给插槽添加一个name(插槽名)
<slot name="插槽名"> 插槽默认内容 </slot>
(2)父组件: 使用 v-slot:插槽名 或 #插槽名
<子组件>
<template v-slot:插槽名>
html结构
</template>
</子组件>
3.作用域插槽: 子组件传递 数据 给父组件插槽
(1)子组件 : 给<slot>内置组件添加自定义属性
<slot 属性名="属性值" > 插槽默认内容 </slot>
(2)父组件 : 使用 v-slot="对象名"
18.写出nextTick的作用,以及用法
作用:获取数据更新之后的dom元素
用法:
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
new Vue({
methods: {
// ...
example: function () {
// 修改数据
this.message = 'changed'
// DOM 还没有更新
this.$nextTick(function () {
// DOM 现在更新了
// `this` 绑定到当前实例
this.doSomethingElse()
})
}
}
})
19.在使用v-for时,为什么需要使用key
(1)1、 key的作用主要是为了高效的更新虛拟DOM,其原理是vue在patch(补丁)过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
2、 另外,若不设置key还可能在列表更新时引发一些隐蔽的bug。如某行数据不该更新的却更新了。
3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
(2)key唯一标识符定义不同的key值,告诉虚拟dom两个元素不一样可以直接替换了,列表过渡必须要有key如果两个相同的元素切换,会发现不能触发过渡效果,这是因为vue里面的diff算法和虚拟dom的元素,可以使用key=‘’设置不同的值来解决