这段时间用Vue开发项目,看了很多关于vue的知识点,有从别的大佬那里借鉴的理解,也有自己的理解。在这里做一个简单的总结,再加深一下印象。也希望可以帮助到有需要的同学。理解错误的地方,欢迎指正。
1、你怎么理解Vue是一套渐进式框架这句话
答:Vue是渐进的,可以理解成它可以逐步的去添加你想要的功能,跟Angular和React相比它没有强主张,是个轻量视图。
2、Vue有两个核心分别是什么?
答:数据驱动和组件化。
(1)数据驱动是ViewModel ,使数据和视图保持一致。
(2)组件化可以提高代码的复用性,降低模块间代码的耦合度。
3、 Vue为什么要操作虚拟DOM?
答:虚拟DOM是用一个对象来描述真实DOM。一个真实的DOM上面有非常多的属性,操作起来非常不便。为了减少DOM操作,我们在更新的时候把需要更新的DOM先记录下来,然后更新这些需要更新的DOM,最后再根据diff算法比对,更新DOM。(vue里的diff算法是平级比较)虚拟DOM不依赖真实的平台环境,可以实现跨平台。
4、Vue中的模板编译原理是什么?
答:模板指的就是template。如果我们传了一个template,我们会把template转换成一个render函数,然后通过render函数返回虚拟DOM,再把虚拟的DOM变成真正的DOM。
5、 响应式数据的原理是什么?
答:响应式就是当数据变化的时候,可以让视图也同步更新。核心是Object.defineProperty,Vue初始化的时候,Object.defineProperty依次会给data的属性上增加get和set方法,并对依赖进行收集,如果数据发生变化,就会去通知相关的依赖做出对应的更新。
6、Vue 的双向绑定的原理是什么?
答:vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。
7、Vue 的双向绑定的实现步骤是什么?
(1)Observer(监听器),劫持并监听所有属性,如果有变动,就通知Watcher。
(2)Watcher(订阅者),收到属性变化的通知并执行相应的函数更新视图。
(3)Compile(解析器),解析模板指令,并替换模板的数据,根据模板数据去初始化相应的订阅器。
8、 Vue的生命周期钩子是如何实现的?
答:Vue的生命周期钩子就是一个回调函数。当我们传入一个钩子函数时,Vue内部会帮我们调用,并将生命周期钩子转换成数组,调用的时候,就又会把数组遍历一遍。
9、Vue的生命周期钩子函数有哪些?
(vue2.0)
答:
(1) 创建期间的生命周期函数:
beforeCreate():此时,实例在内存中刚刚创建出来,data和methods没 有被初始化。
created():此时,实例已经在内存中创建完成,data和methods已经被初始化完成。模板还没有编译。
beforeMount():此时,模板已经编译成功,还没有挂载到页面上。
mounted():此时,编译好的模板已经挂载到了指定的位置上去。
(2)运行期间的生命周期函数:
beforeUpdate():此时,data数据发生改变后,还没有重新渲染DOM树,data的数据是最新的,但是页面上展示的还是旧数据。
updated():此时,data中的数据和页面中的渲染是一致的。
(3) 销毁期间的生命周期函数:
beforeDestroy():此时,实例的方法、指令都还可以使用,实例销毁之前调用。
destroyed():此时,vue实例上的所有指令、绑定、监听都会被销毁,子实例也全部被销毁。
10、请说出至少 4 种 Vue 当中的指令和它的用法
答:
(1) v-bind(属性绑定)
(2) v-on(事件绑定)
(3) v-model(双向数据绑定)
(4) v-for(遍历)
(5) v-if(判断是否隐藏)
11、v-for 与 v-if 的优先级
答:v-for优先级高于v-if。
12、v-if 和 v-show 有什么区别?
答:这两个指令都是在判断DOM节点是否显示。区别是:
(1)实现方式: v-if是根据后面数据的真假值判断直接从DOM树上删除或重建元素节点。 v-show只是在修改元素的display的属性值,元素还在DOM树上。
(2)编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件和子组件; v-show只是简单的基于css切换;false
(3)编译条件:v-if是惰性的,如果初始条件为false,就什么都不做;当条件第一次变为true的时候才会局部编译; v-show是在任何条件下都被编译,而且DOM元素始终被保留;
(4)性能消耗:v-if有更高的切换消耗,不适合做频繁的切换; v-show有更高的初始渲染消耗,适合做频繁的切换;
13、v-on可以监听多个方法吗?
答:可以,写法如下段代码
14、Vue常用的修饰符有哪些?
答:Vue修饰符主要有:
(1)事件修饰符
.stop:和原生JavaScript中的event.stopPropagation()一致,阻止事件冒泡
.prevent:和原生JavaScript中的event.preventDefault()一致,阻止默认事件
.capture:与事件冒泡的方向相反,事件捕获由外到内
.self:只会触发自己范围内的事件,不包含子元素
.once:只会触发一次。
(2)按键修饰符
.delete 捕获“删除”和”退格“键
v-on:keyup.xxx=’yyy’
(3)系统修饰符
.ctrl .alt .shift .meta这些修饰符,按下相应键触发鼠标或键盘事件
15、Vue中子组件如何调用父组件里面的方法?
答:
(1) 直接在子组件中通过this.$parent.event
来调用父组件的方法。
(2) 在子组件里用$emit
向父组件传递一个事件,父组件监听这个事件。
16、Vue中父组件如何调用子组件里面的方法?
答:
父组件利用ref属性操作子组件方法。
父组件:
子组件:
test() {
console.log('你好')
}
}
在父组件里调用子组件的test方法:this.$refs.childMethod.test()
17、Vue组件之间如何传递参数?
答:
(1)使用prop传递参数
第一步 在父组件中动态绑定属性(注:该属性需在data中声明)
第二步 在子组件中定义props接收动态绑定的属性props: ['dataList']
注:props也可以定义成一个对象
props: {
id: String,
formData: {
type: Object,
default: () => {},
required: false,
},
formBpm: {
type: Boolean,
default: false,
required: false,
},
在子组件中获取父组件中的属性和方法需要使用:this.$parent.
属性名 或this.$parent.
方法名。
(2)使用ref传递参数
父组件调用子组件的属性或方法时需绑定ref
属性
在父组件中使用this.$refs.parent.
属性名或this.$refs.parent.
方法名
(解释:ref如果绑定在组件上,指向的是组件实例,使用$ref
可以获取到定义在组件上的属性和方法。ref如果绑定在DOM上,那么指向的就是这个DOM元素,使用$ref
就能获取到这个元素的属性。)
(3)使用emit传递参数
子组件向父组件通信需要调用this.$emit
(方法名,参数)
解释:$emit方法绑定了一个自定义的event事件,当代码语句正常执行到event事件时,就会把event后面的参数传递给父组件。父组件通过@event监听并接收传递的参数
(4)其他方法传值
① 路由跳转传递参数,vue-router。
② 本地缓存,localStorge。
③ 使用vuex数据管理传参。
18、prop和ref的区别是什么?
答:prop不能调用子组件的属性和方法,主要用于数据的传递。
ref主要用于调用子组件的属性和方法,并不擅长传递数据。
19、怎么定义vue-router的动态路由?怎么获取传过来的值?
答:动态路由的创建,使用path属性,使用动态路径参数,以冒号开头:
{
path: '/test/:id' // :id就是传递的参数
name: 'Test'
components: Test
}
渲染/test下的路由时,id参数会被放this.$route.params
里面。通过this.$route.params.id
可以动态获取参数。
20、$route
和 $router
的区别是什么?
答:
(1) $route
是路由信息对象跳转的路由对象,每一个路由都会有一个route对象,是一个局部对象,里面包含:path、params、hash、query、fullPath、matched、name等路由参数。
(2)$router
为VueRouter的实例,是一个全局路由对象,包含了路由跳转的方法、钩子函数等。
21、 vue-router 如何传递参数?
答:
(1)使用Params:参数不会显示在路径上,浏览器强制刷新参数会被清空
// 传递参数
this.$router.push({name:" demo", params: {id:111}})
// 接收参数
this.$router.params.id
(2) 使用Query:参数会显示在路径上,刷新时参数不会被清空
// 传递参数
this.$router.push({path: '/demo', query: {id:111}})
// 接收参数
this.$router.params.id
注:使用params时要用name,使用path时要用query
22、vue-router如何响应路由参数的变化?
答:
(1) 用watch 监听$router
对象。
watch: {
$router(to, from) {
// 对路由变化作出响应
}
}
(2) 使用导航守卫,组件内beforeRouteUpdate(to,from,next)导航钩子函数。
beforeRouteUpdate(to,from,next) {
// 对路由变化作出响应
}
23、什么是导航守卫?
答:导航守卫(路由守卫),可以理解成是路由拦截,用来判断用户是否登录,是否有权限浏览等。
24、导航守卫有哪几种?
答:(1)全局守卫:beforeEach相当于一座大厦的入口,要进来需要过安检。需要知道你是从哪来的,要去哪。
router.beforeEach((to, from, next)=>{
console.log(to) // 要跳转到哪个页面
console.log(from) // 从哪个页面跳转过来的
})
(2)组件内导航守卫:beforeResolve
(3)独享守卫:beforeEnter
原理:
当一个导航触发时,全局守卫依次调用(异步)。此时导航在所有守卫 resolve 完之前都处于等待状态。每个守卫方法接收三个参数:to, from, next
to: 即将要进入的目标 路由对象
from: 当前导航正要离开的路由
next: 是一个回调函数, 一定要调用该方法来 resolve 这个钩子。
解释next的情况:
(1)next(false): 中断当前的导航。如果用户手动点击浏览器的回退按钮,此时的url会发生变化,url会找到 from对应的地址。
(2)next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
(3)next(error): 如果传入 next 的参数是一个 error,导航会被终止。
25、 Vue中nextTick的实现原理是什么?
答:nextTick中的回调函数是在下一次DOM更新结束之后执行的,延迟回调,而防止多次更新。(nextTick里面是一个promise)。
26、keep-alive内置组件的作用是什么?
答:keep-alive是vue内置的一个组件,这个组件的作用就是用来缓存不活动的组件,组件进行切换的时候,默认会进行销毁,如果有需求,某个组件切换后不进行销毁,而是保存之前的状态,那么就可以利用keep-alive来实现。
27、 vue.set方法怎么理解?怎么使用?
答:vue不允许在已经创建的实例上动态添加新的根级响应式属性,$set可以触发更新,当对象新增不存在的属性时,会触发对象依赖的watcher去更新,当更改数组索引时,我们调用数组的splice方法去更新数组。
操作数组示列:
this.$set(arr, index, val)
操作对象示例:
this.$set( obj, key, val)
28、 vue.mixin的使用场景和原理是什么?
答:vue.mixin可以增加公共方法,当组件初始化调用的时候,mergeOptions方法会进行合并,并针对不同的属性进行合并。vue.mixin的缺点:依赖问题、命名问题、数据不能共享、数据来源等问题。
29、vue中 key 值的作用是什么?
答: key的作用主要是为了高效的更新虚拟DOM。在vue中,当使用相同标签名元素的过渡切换时,也会使用到key属性,这样是为了让vue区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
30、Vue 组件中 data 为什么必须是函数?
答:在 new Vue() 中,data 是可以作为一个对象进行操作的,在 component 中,data 只能以函数的形式存在,不能直接将对象赋值给data 。 当data是一个函数时,每个实例可以维护一个被返回对象的独立的拷贝,各个实例中的data都是独立的,不会相互影响。
31、vue的动态组件怎么理解?
答:就是多个组件通过同一个挂载点进行组件的切换,is的值是哪个组件的名称,那么页面就会显示哪个组件。
32、vue中是如何检测数组变化的?
答:vue将数组原型上的方法进行了重新编写,更改了push、shift、pop、splice、unshift、sort、reverse等方法,这些方法都可以改变数组原来的值。当我们用了这些方法来操作数组时,就会把原来的方法进行劫持,可以在函数内部添加自己的功能。如果想更新数组的索引,需要使用vue.$set方法来实现。
33、递归组件怎么使用?
答:在export default中,需要有name属性。递归组件只能通过 name 属性来进行操作。(注:递归组件一定要有一个结束条件,否则就会出现栈溢出的错误。可以添加v-if="false"作为递归组件的结束条件。)
34、Vue.js中ajax请求应该写在组件的methods中还是vuex的actions中?
答:
(1) 如果请求来的数据不需要被其他组件复用,只在请求的组件内使用,就不需要放入vuex 的state里。
(2) 如果被其他地方复用,就可以把请求放入action里,包装成promise返回,在调用的地方用async await处理返回的数据。
35、Vuex是什么?什么情况下我们应该使用Vuex?使用Vuex有什么好处呢?
答:
(1)Vuex是一个专为Vue应用程序开发的状态管理模式。它可以实现组件全局状态的数据共享。
(2)当开发一个大中型的单页面应用,组件之间需要数据共享时可以使用Vuex。
(3)Vuex可以集中管理共享数据,易于开发和后期的维护。可以高效的实现组件之间的数据共享,提高开发效率。而且存储在Vuex里面的数据都是响应式的,可以保持数据与页面一致。
36、如果不使用Vuex会有什么问题?
答:
(1)不使用Vuex的状态下,想要大范围、频繁的共享数据的话,是非常麻烦的。修改数据的时候,会牵扯到很多组件,需要维护很多地方,降低了可维护性。
(2)由于对数据的来源不明确,导致代码的可读性降低。
(3)增加了组件之间的耦合度,和Vue的设计初衷相抵触了。
37、vuex的主要核心概念有哪些?
答:State、 Mutation 、Action、Getter
(1)State
它是用来提供唯一的公共数据源的,所有共享的数据都要统一放到store的State里进行存储。State类似于Vue里面的data,都是存放数据源的。但是State里面的数据是响应式的。如果State里面的数据发生了变化,那么所有依赖该数据的组件都会更新。
// 首先要先创建一个store,提供唯一公共数据
const store = new Vuex.Store({
state: { // state对象里面的数据就是需要全局共享的数据
数据名: 值,
}
})
// 组件需要访问State中的数据时的方法1:
this.$store.state.数据名
// 组件需要访问State中的数据时的方法2:
// 首先按需导入mapState函数
import { mapState } from 'vuex'
// 将全局数据映射到computed上
computed: {
...mapState(['数据名'])
}
(2)Mutation
在Vuex中,不允许组件直接通过this.$store.state
修改全局数据。Mutation 用于变更Store中的数据,并且只有使用Mutation 才可以修改Store里面的数据。这样可以集中管理全部数据的变化。
// 定义Mutation
const store = new Vuex.Store({
state: { // state对象里面的数据就是需要全局共享的数据
数据名: 值,
},
mutations:{
事件名(state) { // 这里需要传递一个state参数
// 变更数据的方法
state.数据名+你接下来想要做的事
}
}
})
// 在组件中调用Mutation 的方法1:
methods: {
demo() {
this.$store.commit('事件名')
}
}
// 在组件中调用Mutation 的方法2:
// 首先按需导入mapMutation 函数
import { mapMutation} from 'vuex'
// 将mutations函数映射到methods上
methods: {
...mapMutation(['事件名'])
}
(3)Action
它用来处理异步任务,可以在异步任务中携带参数。如果异步操作需要变更数据,必须通过Action,不能直接用Mutation。其实Action在改变数据的时候,也是需要出发Mutation来间接的改变数据。
// 定义Action
const store = new Vuex.Store({
state: { // state对象里面的数据就是需要全局共享的数据
数据名: 值,
},
mutations:{
事件名(state) { // 这里需要传递一个state参数
// 变更数据的方法
state.数据名+你接下来想要做的事
}
},
actions: {
async(参数) {
参数.commit('事件名')
}
}
})
// 调用Action的方法1:
methods:{
demo() {
this.$store.dispatch('async')
}
}
// 调用Action的方法2:
// 首先按需导入mapActions 函数
import { mapActions } from 'vuex'
// 将actions函数映射到methods上
methods: {
...mapActions(['async'])
}
(4)Getter
它用于对Store里面的数据进行加工处理,并且形成新的数据。类似Vue里面的computed。如果Store里面的数据发生变化,那么Getter里面的数据也会跟着变化。
// 定义Getter
const store = new Vuex.Store({
state: { // state对象里面的数据就是需要全局共享的数据
数据名: 值,
},
getters: {
demo: state => {
// 你想要做的操作
}
}
})
// 调用getter的方法1:
this.$store.getters.demo
// 调用getter的方法2:
// 首先按需导入mapGetters函数
import {mapGetters} from 'vuex'
// 将getters函数映射到methods上
computed: {
...mapGetters(['demo'])
}