# Vue

# 1.生命周期?

  • 生命周期就是vue实例从创建到销毁的过程。总共分为8个阶段(创建前后,载入前后,更新前后,销毁前后)
  • 在beforeCreate阶段,el(挂载元素,实例)和data还没初始化完成
  • created阶段,data初始化完成,可以访问方法和数据。但是el还没初始化完成
  • beforeMount阶段,el也初始化完成,可以获取dom节点,但不能操作
  • mounted阶段,挂载完毕,可以操作dom节点
  • 数据变化触发beforeUpdate和updated
  • beforeDestroy阶段,可以销毁定时器和绑定的事件(此时实例还是可用的)
  • destroyed阶段,改变data不会触发生命周期函数(dom 结构依然存在)

# 第一次页面加载会触发哪几个钩子?

beforeCreate, created, beforeMount, mounted

# dom渲染在哪个周期完成?

mounted中就完成了

# 挂载和创建的区别?

创建之后只可访问数据不可操作dom,挂载后可以访问数据操作dom

# vue生命周期钩子函数有哪些?

beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed,activated,deactivated, (errorCaptured当捕获一个子孙组件的错误时会调用)

# 2.v-if和v-show的区别?

  • v-if实际是dom元素的创建和销毁
  • v-show实际操作的是css的display属性 none/block (v-show还减少了diff的对比,能优化操作中的性能)

# 3.vue组件封装 全局可用?

在main.js引入,在使用的vue文件中直接即可

import Swiper from './components/Swiper.vue'
Vue.component("my-swiper", Swiper)
1
2

# 4.vue中的data为什么是个函数?

组件之间共享data属性,如果不用函数写法,data的值会指向同一个引用地址,改变一个会影响其他 (函数写法,保证每次返回的都是一个新的对象,组件之间互相不影响)

# 5.深度监听?

watch: {
    a: {
        deep: true, // 开启深度监听
        handler() {
            
        }
    }
}
1
2
3
4
5
6
7
8

# 6.keep-alive作用?

=》首次进来还是会走created和mounted

  • 组件间动态切换时缓存被移除的组件实例,缓存后会走activated和deactivated,像created和mounted和destroyed是不走的(组件被缓存起来了)
  • activated页面或组件被缓存每次进入页面会触发。deactivated组件离开触发

# 例子

  • 路由从列表组件跳到详情页组件,再跳回列表组件,会重新渲染。可以通过缓存提高性能。
  • 可以实现分页后查看详情再跳回列表时,回到原来所在的页面

# 7.vue-router传参?

  • this.$router.params.id获取动态路由的参数/user/:id
  • this.$router.query.id获取?后拼接的参数/user?id=123

# 这两种方式传参有什么区别

params传参只能通过name,如果写成path:‘/xxx’,获取的参数是 undefined query可以通过name和path获取参数 query传参可以在地址栏看到,params不可以

# 8.vue的数据流?

vue的数据流是单向的

# vue是单向数据流,怎么v-model又是双向绑定?

vue数据流是单向的,由父节点传给子节点。

# 9.v-router路由守卫有哪些参数,如何实现?

路由守卫分成全局守卫,路由独享守卫,组件内路由守卫

  • 全局前置守卫beforeEach(to,from,next)
  • 路由独享守卫beforeEnter(to,from,next)
  • 组件内路由守卫beforeRouteEnter(to,from,next),beforeRouteUpdate(to,from,next),beforeRouteLeave(to,from,next)
  • 全局解析守卫beforeResolve(to,from,next)
  • 全局后置守卫afterEach(to,from)
# 没有导航切换:
  • beforeEach->beforeEnter->beforeRouteEnter->beforeResolve->afterEach
# 有导航切换:
  • beforeRouteLeave->beforeEach->beforeRouteEnter->beforeResolve->afterEach
# 完整导航解析流程(来自官网)
  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

# 10.vuex有哪些参数,作用?

vuex是vue的状态管理。主要用来解决各组件间传值复杂和状态混乱的问题 =》无法持久化 可以通过localStorage实现

  • state 存放数据,不可以直接修改
  • getter 类似与computed,用来计算
  • mutation 函数,必须是同步方法 动态修改数据
  • action 函数,如果有异步操作可以通过action代替mutation
  • module 分模块,不同模块拥有自己的state,mutation,action,getter
  • namespace 命名空间,声明了命名空间(namespaced: true),使用需要通过命名空间前缀

# VUEX改变全局参数?

异步方法通过dispatch(function)触发action,action再去commit触发mutation修改参数。同步方法直接通过commit触发mutation修改参数

# 注入原理?

通过Vue.use去安装vuex,插件内部有一个install方法,调用install方法把store注入到vuex实例中

# 11.mvvm模型的理解及与MVC区别 => vue-mvvm 当model变化会触发view更新?

  • mvc model数据层 view视图层 controller控制层 各部分之间通信是单向的 view->controller->model->controller->view
  • mvvm 由mvc演变而来 controller演变成viewModel 各部分之间通信都是双向的 当model变化vm会自动更新,view也会自动更新
  • model<->controller model<->view => model和view 不直接进行通信

# 12.v-for为什么一定要绑定key?

  • key主要是用在虚拟dom上,在新旧节点对比时用来辨识节点,
  • 有key的话可以更快的找到对应的节点,没有key的话会采用就地复用的原则
  • 如果数据顺序被改变,vue不会移动元素来调整顺序,而是就地更新每个元素。

# key主要是用来解决什么问题?为什么不建议用index?

尽量不用index作为key,否则在指定位置插入一个新元素,改变了index,这样就会导致后面所有元素都进行更新,因为后面的key都改变了

# 13.vue的inject和eventbus?

provide和inject是成对出现的,用来父组件向子孙组件传值

  provide() { // 父组件
    return {
      type: 'yeye',
      age: 60
    }
  }
  inject: ['age'] // 子孙组件
1
2
3
4
5
6
7
// main.js 定义
Vue.prototype.$eventBus = new Vue()
// 接收
this.$eventBus.$on('update', val => {})
// 发布
this.$eventBus.$emit('update', '更新信息')
// 销毁
this.$eventBus.$off('update', {})
1
2
3
4
5
6
7
8

# 14.vue2和vue3响应式原理实现差异?

  • vue2的Object.defineProperty只能劫持对象属性,而vue3的proxy是直接代理对象(在data中的数据如果不是响应式可以用Object.freeze来冻结对象)
  • vue3不用重写setter和getter方法(不用直接递归)所以性能高

# 15.v-model可以用什么替代?

v-bind+v-on v-on定义事件获取输入的值进行设置,v-bind将这个值显示出来

# 16.vue组件销毁,所有自定义事件($emit,$on定义的事件)和原生事件都会解绑吗?

会自动解绑组件本身的事件,像定时器,addEventListener注册的监听器,都要在beforeDestroy的时候手动解绑

# 17.vue怎么区分开发环境和生产环境?

用webpack定义两套配置,一套开发,一套生产

# 18.如何设置css只在当前组件起作用?

在style标签添加scoped即可。

# 原理

编译后会将所有元素生成唯一的属性或者类名

// 代码
.btn {
}

// 编译后
.btn .jsx-1287234 {
}
1
2
3
4
5
6
7

# 19.vuex怎么做数据响应式?

借用vue的数据响应式来实现。利用vue将state作为data进行响应式处理,使得state发生变化就能重新渲染组件

# vuex和v-model冲突吗?

严格模式,在属于vuex的state上使用v-model会报错。

# 解决方案?

给input中绑定value,监听input或change事件,在回调函数中通过commit来修改数据

# 20.route和router有什么区别?

  • route是路由信息对象,可以通过route获得path,hash,query等路由信息参数
  • router是路由实现对象,可以用来跳转router.push()

# 21.vue是挂载在哪个标签上?

vue是挂载在body标签里面(在vue中获取不到body标签)

# 22.computed和watch区别是什么?

  • computed是计算属性不在data里声明,而watch监听的是data里的属性
  • computed定义的值会进行缓存,watch不会。 (computed缓存是通过一个dirty属性进行控制,只有当其响应式数据发生变化时才会设置为true,触发重新计算)
  • watch监听的是属性值,computed监听的是依赖值。依赖值不变的情况都会直接读取缓存,只有改变了才会重新计算

# 23.vue模版编译原理?为什么要用template?

传递的是template属性,需要将template编译成render函数

  1. 通过正则将模版解析成AST语法树 template=>ast语法树
  2. 从AST语法树中找出静态节点进行标记=》目的是提高虚拟dom用diff算法比对时的性能
  3. (generate递归拼接为字符串)通过AST生成render函数 render函数作用是生成虚拟节点(递归是先子后父)

# 抽象语法树AST和虚拟dom有什么区别?

ast做的是语法层面的转化,虚拟dom描述的是dom元素,可以增加自定义属性

# 24.vue的挂载过程?

  • new Vue的时候会调用init方法,初始化数据,事件,生命周期这些
  • 然后通过$mount里面的mountComponent去执行render生成虚拟dom,再通过update将虚拟dom生成真实dom渲染到页面上

# 25.说说组件传值的几种方式?

  1. 父子通信 props和$emit =>父组件通过props向子组件传递数据,子组件通过$emit通知父组件
  2. 父子通信 $parent和$children =>可以访问该组件所有方法和data。 要注意边界情况。如#app的$parent拿到new Vue的实例,再往上就是undefined。最底层拿$children拿到的是空数组,$children的值是数组,$parent的值是对象
  3. 父子通信 ref和refs =>ref在普通dom元素上使用,指向的就是dom元素,在子组件上使用,指向的就是组件实例,可以直接调用组件方法和data =》vue通过ref来获取和操作dom
  4. 跨级通信 provide和inject =>父组件通过provide提供变量,子孙组件都能通过inject注入变量。 缺点不是响应式,但是如果传入的是可响应的就还是可响应的 =>想要响应式可以通过传入父组件的实例或者是2.6.0新增的Vue.observable()
  5. 全局通信 eventBus =>可以向该中心发送通知和接收通知 =>缺点是项目较大时难以维护 $emit定义事件名称及操作,$on接收该事件名称传递的值
  6. 全局通信 Vuex =>state,getter,mutation,action,module。解决了多个视图依赖同一状态和来自不同视图的行为需要变更同一状态的问题 =>修改state的数据必须通过mutation进行,action也是要通过mutation
  7. 全局通信 localStorage和sessionStorage =>目的是持久化保存,缺点也是数据和状态比较混乱,不易维护 *8. 父子孙通信(跨级通信) $attrs和$listeners => $attrs和$listeners是两个对象,$attrs保存的是父组件中绑定的非props属性,$listener保存的是父组件中绑定的非原生事件 9.兄弟通信 $root

# 26.如何解决vue初始化页面闪动问题?

v-cloak=》v-cloak里面设置display:none

# 27.什么是SPA,有什么优点和缺点?

SPA(single page application)单页面应用,仅在web页面初始化时加载相应的HTML,JS,CSS。 一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转。 =》利用路由机制实现内容切换(hash模式,局部刷新)

# 优点:

用户体验更好,避免了不必要的跳转和重复渲染,相对也能减轻服务器压力

# 缺点:

初次加载耗时多,不利于SEO

# 28.在哪个生命周期发起数据请求?

在created,beforeMount,mounted都可以发起。

# 29.vue-router的几种模式?hash和history有什么区别?

两种:hash和history。默认hash模式,hash模式在url中会存在#符号,history模式不会

  • history需要后端nginx配置,url中的路径就是根目录下的相对路径,如果不用就会返回404
  • hash模式只要index文件是真实路径即可

# 30.vue数据频繁变化,为什么只以最后一次为准?

watcher里面有做去重操作:给每个dep引入id,watcher会记录所有dep的id,下次依赖收集的时候如果dep的id已经存在就不再收集watcher了 =》queueWatcher函数负责把对应的watcher收集到数组queue中,flushSchedulerQueue会从queue中取出watcher,然后执行watcher.run

# 31.vue和react区别?

  • vue和react的diff算法不同 vue对比节点,如果元素类型相同,className不同,认为是不同元素会删除重建,react会认为是同类型节点,只修改节点属性 vue列表比对采用首尾指针,react采用从左到右比对的方式,当集合把最后一个节点移动到第一个,react会把前面的节点依次移动,而vue只会把最后一个移动到第一个
  • 响应式实现原理不同 react通过setState来更新状态=>状态更新后组件也会重新渲染 vue通过defineProperty进行数据劫持再进行更新
  • vue使用template模版编写,react使用jsx编写
  • vue是双向数据流,react是单向数据流
  • vue给我们封装了许多指令,react没有

# 32.v-html有什么问题?

很容易导致xss攻击,不能用于用户提交的内容上

# 33.v-if和v-for为什么不建议混合使用?

被渲染的dom会重复一个创建销毁的过程=>v-for优先级更高,如果数组很大,而实际要展示的很少,造成性能浪费 (当v-for和v-if处于同一个节点时,v-for的优先级比v-if更高)=>通过computed先对要展示的数据进行过滤,再进行v-for

# 34.vue2和vue3区别?

  • 双向绑定原理不同=》vue2通过Object.defineProperty做数据劫持,vue3通过proxy进行代理。defineProperty不能监听数据对象新增的属性=>proxy可以(需要手动$set)
  • vue2是option API vue3是Composition API
  • 生命周期改变(beforeCreate,created->setup(),beforeMount->onBeforeMount,mounted->onMounted,beforeUpdate->onBeforeUpdate, updated->onUpdated,beforeDestroy->onBeforeUnMount,destroyed->onUnMounted,errCaptured->onErrorCaptured) =>把beforeCreate和created合并成setup(),挂载和更新的钩子前面都加上了on,beforeDestroy变成onBeforeUnMount,destroyed变成onUnMounted
  • vue3不使用this,避免了this指向问题。(vue2通过this去指向当前组件实例,vue3没有对this进行绑定)
  • template里面可以使用多个子节点(和react一样,有fragment)
  • vue3更小(移除不常用API,引入tree-shaking)更快(diff算法优化)
  • vue3基于ts编写的,原生支持ts,vue2需要额外配置
  • vue2的diff采用双端diff算法,vue3采用最长递增子序列
  • vue2声明变量在data,vue3使用ref和reactive声明
  • vue2的v-for优先级高于v-if,vue3的v-for优先级低于v-if

# *35.计算属性(computed)和实例方法(method)有什么区别?

  • 计算属性有缓存,实例方法没有
  • 计算属性不能传参数,实例方法可以

# 36.父子组件生命周期?

  • 父beforeCreate=>父created=>父beforeMount=>子beforeCreate=>子created=>子beforeMount=>子mounted=>父mounted
  • 父组件先执行,在beforeMount和mounted之间,子组件执行beforeCreated到mounted
  • 更新过程:父beforeUpdate=>子beforeUpdate=>子updated=>父updated(如果不互相影响,各自执行各自的。如父beforeUpdate=>父updated)
  • 销毁过程: 父beforeDestroy=>子beforeDestroy=>子destroyed=>父destroyed

# 37.非props属性有什么特点,如何解决props层级过深的问题?

非props属性的子属性不能使用该属性 可以使用Vuex解决层级过深

# 38.如何编写可复用的组件?

组件只负责UI的展示和交互,不做具体数据处理,尽可能减少外部依赖

# 39.*插槽slot?

子组件定义插槽,父组件提供内容去填补插槽

  • 默认插槽(匿名插槽)一个组件只能有一个,相对应的是具名插槽,一个组件可以有多个,但是每个名称不同
  • 匿名插槽和具名插槽不绑定数据,作用域插槽要在slot上绑定数据

# 40.如何声明一个过滤器?

全局过滤器:

vue.filter(‘gettime’,function(date){
    Var time=new date(date)
    return time.getFullyear()+’/’+time.getMonth()+1’/’+getDate() }
)
1
2
3
4

# 41.react/vue的router实现原理?

主要有两种实现方式:

  • history API: history.pushState()跳转路由 通过popstate事件监听路由变化(无法监听到history.pushState()的路由变化)

  • hash: location.hash跳转路由 通过hashchange事件监听路由变化

# 区别:

hash只能修改#后的值,history可以随意设置同源url hash的历史记录只显示之前的网址不会显示hash值,而history每条记录都会进入历史记录 hash无需后端配置,而history需要后端配合。比如需要设置一个页面用来匹配找不到资源的情况

# 42.mixin作用?

作用是抽离公共业务逻辑 (本质就是个js对象,将公共功能传入mixins,组件会将mixins对象中的选项和组件本身的合并,就是混入) 混入数据和本身组件数据有冲突,以本身为准

# mixin原理?

主要是调用mergeOptions方法,mergeOptions会先递归处理mixin的数据,赋值给parent =>然后再遍历mergeFiled parent的key,最后再遍历child,如果parent已经处理过这个key,就不处理

var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}
// 局部混入
Vue.component('componentA',{
  mixins: [myMixin]
})
// 全局混入 => 会影响到第三方组件,比较适合用在插件里
Vue.mixin({
  created: function () {
      console.log("全局混入")
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 43.vue.use作用?

是用来使用第三方库的 内部有install方法传入vue(构造函数)=》内部使用vue

# 44.vue中使用的设计模式?

  1. 单例模式 =》只有一个实例
  2. 工厂模式 =》传入参数就可以创建实例
  3. 观察者模式 =》依赖收集
  4. 代理模式 =》proxy

# 45.vue脚手架?

vue-cli=>create-vue

# 46.为什么使用$set?

vue不能监测到对象属性的添加或删除,需要通过$set来实现

# 47.常用修饰符?

表单修饰符

  • lazy(光标离开才赋值,@change事件触发后)、trim、number 事件修饰符
  • stop、prevent、self、once、capture、passive、native 鼠标按钮修饰符
  • left、right、middle 键盘修饰符
  • onkeyup、onkeydown、enter等

# 48.vue-cli帮我们做了哪些事情

1.快速搭建vue项目 2.不用配置就可以启动本地开发服务器 3.有内置配置文件,可以帮我们优化打包

# 49.怎么理解数据驱动

是vue的核心思想,我们对视图的修改不会直接操作dom,而是通过修改数据。(jQuery是直接修改dom)

# 50.v-model实现原理

v-model在组件和原生标签上不同 原生标签: 在不同元素上会有不同编译结果,比如文本,会被编译成value+input+指令。 (value和input会阻止中文触发,此时v-model的值不会在中文输入过程中更新,指令的作用就是处理中文输入完毕后,手动触发更新) 组件: 在父组件的v-model等价于:value="msg" @input="func()" 用value传递props,用input派发事件 (会看一下是否有自定义的prop和event,没有会被解析成:value="value" @input="input()")

# 51.路由缓存产生的原因是什么?

路由只有参数变化时,会复用组件实例

# 52.watch和created谁先执行

如果watch 加了 immediate: true, 就是watch先执行,否则就是created 先执行 (watch不加immediate:true,如果有computed ,vue默认先computed 再执行watch) computed=》mounted=》watch