vue

1、v-if和v-show的区别

v-if 是删除dom结点,而v-show是通过设置display:none,实现的,dom结点还存在

  • v-showfalse变为true的时候不会触发组件的生命周期
  • v-iffalse变为true的时候,触发组件的beforeCreatecreatebeforeMountmounted钩子,由true变为false的时候触发组件的beforeDestorydestoryed方法

性能消耗:v-if有更高的切换消耗

如果需要非常频繁地切换,则使用 v-show 较好

如果在运行时条件很少改变,则使用 v-if 较好

2、v-if和v-for不建议一起用

v-for优先级是比v-if

一起用的话,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)

可以在v-for那个标签的外部进行v-if判断.

如果要把v-if放到v-for标签之内,可以先通过计算属性computed提前过滤掉那些不需要显示的项

3、组件通讯

  • 父子关系的组件数据传递选择 props$emit进行传递,也可选择ref
  • 兄弟关系的组件数据传递可选择$bus
  • 祖先与后代组件数据传递可选择attrslisteners或者 ProvideInject
  • 复杂关系的组件数据传递可以通过vuex存放共享的变量

props 父向子

1
2
3
4
5
6
7
8
9
10
11
12
<Children name="jack" age=18 />

props:{
// 字符串形式
name:String // 接收的类型参数
// 对象形式
age:{
type:Number, // 接收的类型为数值
defaule:18, // 默认值为18
require:true // age属性必须传递
}
}

$emit 子向父

触发自定义事件

  • 适用场景:子组件传递数据给父组件
  • 子组件通过$emit触发自定义事件,$emit第二个参数为传递的数值
  • 父组件绑定监听器获取到子组件传递过来的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//  子
deleteItem(id) {
this.$emit('delete', id)
},
// 父
<List :list="list" @delete="deleteHandler"/>
deleteHandler(id) {
this.list = this.list.filter(item => item.id !== id)
}


// input封装成组件
<CustomInput v-model="searchText" />

<!-- CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>


// vue3的写法
// 默认情况下,v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件。我们可以通过给 v-model 指定一个参数来更改这些名字

<MyComponent v-model:title="bookTitle" />

// 在这个例子中,子组件应声明一个 title prop,并通过触发 update:title 事件更新父组件值:

<!-- MyComponent.vue -->
<script setup>
defineProps(['title'])
defineEmits(['update:title'])
</script>

<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>

$bus 兄弟传值

1
2
3
4
5
6
7
8
9
10
11
12
this.$root.bus.$emit('dong', this.number)  // 触发 dong 事件,并传递 number

// created 生命周期函数:实例创建完成, 但是还没有挂载到 DOM
created: function () {
var that = this // 这里为什么要把 this 保存起来?
this.$root.bus.$on('dong', function (value) {
that.number = value // 因为如果在函数里面的函数直接用this,this的值可能会改变
}) // 上面把 this 赋值给 that,那么 that 就是 Vue实例
}, // 你也可以使用 ES6 中的 箭头函数,这样 this 的值就不会变了
beforeDestory(){
this.$root.bus.off('dong',xxx) // 及时销毁,避免内存泄漏
}

4、生命周期

1、created 和 mouted的区别

created 就是初始化vue的实例,而mounted是页面已经渲染完成

2、父子组件生命周期执行顺序

加载渲染过程

父beforecreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted

更新过程

父beforeUpdate->子beforeUpdate->子updated->父updated

销毁过程

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

5、自定义v-model

1
2
3
<input type="text" v-model="value" />
// 上面是下面的语法糖
<input type="text" :value="value" @input="value = $event.target.value" />

父组件展示部分


子组件CustomVmodel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
------------父组件
<script>
import CustomInput from './CustomInput.vue'

export default {
components: { CustomInput },
data() {
return {
message: 'hello'
}
}
}
</script>

<template>
<CustomInput v-model="message" /> {{ message }}
</template>
-------------子组件
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>

<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>

展示结果

6、$nextTick

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,等队列中所有数据变化完成之后,再统一进行更新

第一个参数为:回调函数(可以获取最近的DOM结构)

第二个参数为:执行函数上下文

通过this.$nextTick()调用

7、动态组件和异步加载

vue 提供了一个内置的 组件,专门用来实现动态组件的渲染。示例代码如下:

默认情况下,切换动态组件时无法保持组件的状态。此时可以使用vue 内置的 组件保持动态组 件的状态。示例代码如下:

异步加载组件

8、mixin 混入

抽离公共逻辑,利于代码复用

定义一个mixin对象,有组件optionsdatamethods属性

优先级

组件 data,methods优先级高于mixin data优先级
生命周期函数,先执行 mixin 里面的,再执行组件里面的

自定义的属性,组件中的属性优先级高于mixin属性的优先级

局部使用

全局使用

问题

变量来源不明确,不利于阅读

多mixin 可能会造成命名冲突

mixin和组件可能出现多对多的关系,复杂度较高

9、v-for中为什么要用key

10、何时使用beforeDestory

11、vuex中action和mutaion的区别

12、vue如何监听数组变化

13、vue常见的性能优化

合理使用 v-show 和 v-if

合理使用 computed

v-for 时加key,以及避免和v-if同时使用

自定义事件、DOM事件及时销毁
合理使用异步组件
合理使用keep-alive

data层级不能太深

14、vue3和vue2的区别?

1、支持ts

2、代码组织更有逻辑

3、支持逻辑复用

15、setup中如何获取vue的实例

通过getCurrentUnstance()这个方法

在setup和其他Composition API中没有this
可通过getCurrentInstance获取当前实例
若使用Options API可照常使用this

16、vue3为何比vue2快

1、Proxy响应式
2、PatchFlag

编译模板时,动态节点做标记

标记,分为不同的类型,如TEXT PROPS

diff算法时,可以区分静态节点,以及不同类型的动态节点

3、cacheHandler

缓存事件

4、SSR 优化
5、hoistStatic

将静态节点的定义,提升到父作用域,缓存起来

多个相邻的静态节点,会被合并起来

典型的拿空间换时间的优化策略

6、tree-shaking

动态引入需要的内容,不需要的不引入进来

17、vue和react的区别

1、框架比较

vue简单、上手容易、框架功能完善。

react学习成本高、框架功能强大、很灵活、社区资源丰富。

2、监听数据方式不同

vue通过响应式的setter、getter监听数据

react数据不可变,需要setState驱动新的state替换老的state

3、diff算法不同

相同点:
Vue和react的diff算法,都是不进行跨层级比较,只做同级比较

不同点:

  1. vue会在patch函数中给被操作的节点打补丁(patchflag),在diff的时候更清晰
  2. vue对比节点,当节点元素类型相同,但是className不同时,认为是不同类型的元素,删除重新创建;而react则认为是同类型节点,进行修改操作
  3. diff策略,vue的性能优于react

4、jsx和template

18、vue3 v-for动态绑定ref问题

在setup中可以收集到到元素的ref引入,但是当childApp变化时如删除,新增,childAppRefs会push重复的元素。

不过不一定非得用数组,你也可以用个对象来装,以索引为 Key、然后过滤掉比数据源数组长度还大的那些 Key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<child v-for="(item, index) in list" :ref="el => setChildRef(el, index)" />

<script setup>
// 你也可以抽成一个 hooks,用起来更方便
const childRefs = {}
const computedChildRefs = computed(() => {
return Object.entries(childRefs)
.filter(([index, ref]) => +index < list.length && !!ref)
.map(([_, ref]) => ref)
})
const setChildRef = (el, index) => {
childRefs[index] = el
}
</script>