Skip to content

面试题

基础图

vue

vue 常见的修饰符有哪些?

vue 的修饰符分为事件修饰符和按键修饰符,修饰符支持链式书写。

事件修饰符

  • .stop 停止传递
  • .prevent 提交事件将不再重新加载页面
  • .self 仅当 event.target 是元素本身时才会触发事件
  • .once 事件至多被触发一次,监听器被调用一次后就被移除

watch 和 computed 区别

computed 计算属性更侧重于值更新引发的 更新,而 watch 更侧重于值更新引发的 事件

计算属性的计算值会被缓存,所以对 DOM 的更新影响可能会少一些。计算属性不支持异步操作。 使用监听属性,支持在函数中写异步操作,当属性的值更新时候就会触发对应的操作。

  • 计算属性默认只有 getter 函数,也就是说默认是只读的,但是可以通过写 get 来实现可写:
js
const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  },
  // setter
  set(newValue) {
    // 注意:我们这里使用的是解构赋值语法
    [firstName.value, lastName.value] = newValue.split(' ')
  }
  • 监听属性有两个的参数:
    • immediate:组件加载立即触发回调函数
    • deep:深度监听

vue 中数据双向绑定的原理?

v-model 分为两种,一种是放在原生标签上,另一种是放在 vue 的组件标签上面。

  • 当放在原生标签上的时候,是通过 addEventListener 来实现 DOM 属性(如 input.value)变化的时候,js 变量 同时更新的。然后由于这个 js 变量是响应式数据,所以在他更新的时候同时也会更新相应的 DOM 属性
  • 当放在 vue 标签上的时候,有两个版本,区别如下。

通过子组件定义一个宏 defineModel() 来接收要双向数据绑定的数据:

vue
<script setup>
const model = defineModel()
</script>

<template>
  <button @click="model = '233'">to 12</button>
  child: {{  model }}
</template>

这里的 model 并不是 prop,它并不是只读的,可以修改。根据官方文档,这实际上是一种语法糖,他会展开为:

js
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const model = ref({
  get value() {
    return prop.modelValue;
  },
  set value(val) {
    emit('update:modelValue', val);
  }
})

这和之前的使用是 存在差异 的。这里的 emit 事件,会自动在 model 被更新的时候触发,也就是说,它是事先写好的。之前由于没有事先写好,我们需要在模板中主动的调用 emit 事件:

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

<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

而现在只需要使用 v-model 将子组件中的 model 变量和目标 DOM 双向绑定:

vue
<template>
  <input v-model="model" />
</template>

<script setup>
const model = defineModel()
</script>

两种方式的 数据绑定原理 不同。

多个 modelValue

多个数据绑定的话可以使用:

vue
<!-- 父组件 -->
<MyComponent v-model:title="xxx" />


<!-- 子组件 -->
<script setup>
const title = defineModel('title', , { required: true })
</script>

<!-- 该子组件将被展开为 -->
<script setup>
const props = defineProps({
  title: {
    required: true
  }
})
const emit = defineEmits(['update:title'])
const title = ref({
  get value() {...}
  set value() {...}
})
</script>

vue3 的生命周期有哪些?

  • 在选项式 API 中,有 beforeCreate 和 created 两个创建相关的生命周期。

  • 在组合式 API 中,每个生命周期都以 on 开头:

挂载相关 onBeforeMount, onMounted/keep-alive 中可以换 onActivated;

卸载相关 onBeforeUnmount, onUnmounted/keep-alive 中可以换 onDeactivated;

更新相关 onBeforeUpdate, onUpdated;

vue.nextTick 的作用?

我们知道 vue 是响应式的,当一个数据发生变化的时候,会自动的刷新依赖该数据的 DOM。但是这个刷新实际上是异步的,也就是说,vue 模仿事件循环,在数据发生变化的时候,并不立即更新,而是把它们放到一个任务队列中,在一段时间后任务队列中积累足够多的 DOM 更新后才统一处理。这样做的好处就是提高了页面的响应速度。而 nextTick() 函数可以传入一个回调函数,该函数在 vue 处理完 DOM 更新之后调用。

它主要用于在组件的某数据被更新后,进行一些操作。相对应的,如果是需求是每次组件对应的 DOM 更新,都要进行某些操作,就是用 updated() 生命周期钩子。

CSS

如何实现响应式布局?

  • 使用一些相对单位,比如 rem(相对于根元素) 和 em, vw 和 vh, 百分比
  • 使用媒体查询
  • 使 flex 弹性盒子
  • 使用现有的组件库,比如 bootstrap