VuePressVuePress
vue2
vue3
React
css
javascript
实操题目
http
真题
事件循环
题目
vue2
vue3
React
css
javascript
实操题目
http
真题
事件循环
题目

vue3 比 vue2 有什么优势?

  1. 性能更高
  2. 体积更小
  3. ts 支持
  4. 更好代码组织
  5. 更好逻辑代码抽离

vue3 的声明周期

2 和 3 的区别

  1. beforeDestory 改成 beforeunmount
  2. destoryed 改成 unmounted
  3. 其他沿用 vue2 的生命周期

vue3生命周期

ref, toRef , toRefs

  1. ref: 创建一个响应式对象
  2. toRef 将一个响应式对象的某个属性抽离出来,单独做成响应式对象
  3. toRefs 将响应式变成普通对象

vue3 更新了哪些功能

  1. ts
  2. 异步组件的写法
  3. 移除了 filter
  4. teleport
  5. Suspense
  6. Composition API
  7. template 多节点

组合式写法

export default {
  setup(props, context) {
    // ...
  }
}

选项式写法

export default {
  data(){ 
    return {
      ...
    }
  },
  methods:{...}
}

Composition API 逻辑复用

  1. 可以 自定义 useXXX 逻辑复用
  2. reactive
  3. ref 相关
  4. setup ...

vue3.4 更新了哪些功能?

  1. 解析器速度提高 2 倍,SFC 构建性能提升

  2. 更高效的响应式系统

  const count = ref(0)
  const isEven = computed(() => count.value % 2 === 0)
  watchEffect(() => console.log(isEven.value)) // true
  count.value = 2 // true
  // 3.4 之前只要 count发生变化,即使变化的值是一样的,watchEffect 也会触发
  // 3.4+ 只有发生实际变化,才会触发
  1. defineModel 例子解释

  2. v-bind的同名缩写

 <img :id="id" :src="src" :alt="alt">  
  =>  
  <img :id :src :alt>  
  1. watch 新增 once 检测一次变化 则失效
  watch(someRef, () => {
    // 这个函数只会在 someRef 第一次变化时执行
  }, { once: true });

6. ...

vue3.5 更新了哪些功能?

  1. 子组件的props可以解构
const { msg = '' } = defineProps({
  msg: String,
})
// msg = ''的操作 相当于 withDefaults 了
  1. userId 创建唯一的Id
  2. onWatcherCleanup 清除监听
  3. watch 第三个参数 增加 deep:大遍历深度的数字
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount, onCleanup) => {
    /* ... */
    onCleanup(()=>{ 
      // 清理逻辑
    })
  },
  {
    immediate: true,
    deep: 3, // Boolean | Number (新增)
    flush: 'pre' // 刷新时机 
  }
)
  1. Teleport 将其插槽内容渲染到 DOM 中的另一个位置。
interface TeleportProps {
  /**
   * 必填项。指定目标容器。
   * 可以是选择器或实际元素。
   */
  to: string | HTMLElement

  /**
   * 当值为 `true` 时,内容将保留在其原始位置
   * 而不是移动到目标容器中。
   * 可以动态更改。
   */
  disabled?: boolean

  /**
   * 当值为 `true` 时,Teleport 将推迟
   * 直到应用的其他部分挂载后
   * 再解析其目标。(3.5+)
   */
  defer?: boolean
}

//  <Teleport defer to="#late-div">...</Teleport>

  1. useTemplateRef 获取 dom 节点
  2. 降低了 56% 的内存占用,部分场景能达到 10 倍的性能提升

setup 函数 参数有哪些?

// 当前的context是非响应式的,可以结构出来单独使用
setup(props,context) {
  const { 
        attrs, // 透传 Attributes(非响应式的对象,等价于 $attrs)
        emit,  // 插槽(非响应式的对象,等价于 $slots)
        slots,  // 触发事件(函数,等价于 $emit)
        expose  // 暴露公共属性(函数)
  } = context

  // attrs 和 slots 都是有状态,但是他们的属性不是响应式 他们总会随着组件自身的更新而更新, 
  // 避免解构, 可以通过attrs.x 或者 slots.x 获取
}

render 函数 (setup)

在 Vue 3 中,render 函数的参数有所变化,主要是为了在有状态组件和函数式组件之间保持一致性。以下是新增的几个关键参数:

  1. props:包含传递给组件的所有属性。这个参数使得在 render 函数中可以直接访问组件的 props。

    render(props) {
        return h('div', props.message);
    }
    
  2. slots:包含传递给组件的所有插槽内容。可以通过 slots 参数来访问和渲染插槽。

    render(props, { slots }) {
        return h('div', slots.default ? slots.default() : 'No content');
    }
    
  3. attrs:包含传递给组件但未声明为 props 的所有属性。可以通过 attrs 参数来访问这些属性。

    render(props, { attrs }) {
        return h('div', { ...attrs }, props.message);
    }
    
  4. emit:用于触发自定义事件。可以通过 emit 参数来触发组件的事件。

    render(props, { emit }) {
        return h('button', { onClick: () => emit('customEvent') }, 'Click me');
    }
    
  5. expose:函数用于显式地限制该组件暴露出的属性

 render(props, { expose }) {
    // 让组件实例处于 “关闭状态”
    // 即不向父组件暴露任何东西
    expose()

    const publicCount = ref(0)
    const privateCount = ref(0)
    // 有选择地暴露局部状态
    expose({ count: publicCount })
}

这些参数使得 render 函数在处理组件的属性、插槽和事件时更加灵活和直观。

vue3 如何实现 响应式

  • proxy 不能兼容所有的浏览器, 不支持 polfill
  • vue3 proxy set get Reflect
const proxy = new Proxy(obj, {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    return Reflect.set(target, key, value, receiver);
  },
});

reactive 了解

  1. 创建响应式的对象的
  2. 想要避免深层响应式转换,只想保留对这个对象的顶层访问的响应性,需要 shalldowReactive()替代

watch 和 watchEffect 的区别?

  1. 俩者都可以监听属性
  2. watch 需要明确监听属性
  3. watchEffect 自动监听

setup 如何获取组件的实例

const app = getCurrentInstance();

vue3 使用 v-for 中使用 index 作为 key, 什么情况用 id 作为 key?

  1. 简单列表:当列表项不会动态增删或重新排序时,可以使用 index 作为 key。
  2. 当列表项会动态增删或重新排序时

vue3 中 v-if 和 v-for 可以混用吗? 那个优先级高?

可以混用, v-if 优先级更高

<script setup> 中父组件如何获取子组件的变量

defineExpose

  • <script setup>的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

vue3 中如何在全局中绑定变量或者方法?

  • 设置
// vue3: 
app.config.globalProperties.msg = "hello"; 

// vue2: 
Vue.prototype.msg = "hello";
  • 获取
// vue3
const { proxy } = getCurrentInstance() as any
// console.info(33, proxy.msg)

// vue2: 
this.$msg

pinia 中如何修改 数据

state/getters/actions

  1. 直接修改
const store = useStore();
store.someState = "newValue";
  1. 这是最推荐的方法,通过定义 actions 来修改状态,保持代码的清晰和可维护性。
// 在 store 中定义 action
const useStore = defineStore("main", {
  state: () => ({
    someState: "initialValue",
  }),
  actions: {
    updateSomeState(newValue) {
      this.someState = newValue;
    },
  },
});

// 在组件中调用 action
const store = useStore();
store.updateSomeState("newValue");
  1. 使用 $patch 方法, $patch 方法可以同时修改多个状态值,推荐使用这种方法。
const store = useStore();
store.$patch({
  someState: "newValue",
  anotherState: "anotherValue",
});
  • 传入一个函数来修改状态:
store.$patch((state) => {
  state.someState = "newValue";
  state.anotherState = "anotherValue";
});

vue3 createApp 作用是什么?

在 Vue 3 中,createApp 是一个全局 API,用于创建和初始化 Vue 应用实例。与 Vue 2 中的 new Vue 不同,createApp 返回的是一个应用实例,而不是根组件。这一设计使得在同一个页面中可以创建多个 Vue 应用实例,提供了更大的灵活性。

以下是 createApp 的主要作用和使用步骤:

  1. 创建应用实例:通过 createApp 方法创建一个 Vue 应用实例,并将根组件传递给它。 第一个参数:根组件 第二个参数:rootProps

    import { createApp } from "vue";
    import App from "./App.vue";
    
    const app = createApp(App);
    
  2. 挂载应用:使用 mount 方法将应用实例挂载到 HTML DOM 中的某个元素上。

    app.mount("#app");
    

    对应的还有 onUnmount 注册 卸载时候调用的方法

  3. 安装插件:通过应用实例的 use 方法,可以安装插件。

    import myPlugin from "./myPlugin";
    
    app.use(myPlugin);
    
  4. 创建多个应用实例:在同一个页面中,可以创建多个 Vue 应用实例。

    const app1 = createApp(App1);
    app1.mount("#app1");
    
    const app2 = createApp(App2);
    app2.mount("#app2");
    

通过 createApp 方法,开发者可以更灵活地管理和初始化 Vue 应用,特别是在需要多个应用实例或使用插件的场景中。

provide/inject

  app.provide('test', '我是从 main 传递下来的数据')
  const injectData = app.runWithContext(() => {
    return inject('test')
  })
  console.info('injectData--main', injectData)

  // test.vue 
  import { inject } from 'vue'
  const injectData = inject('test')

如何将某个元素为html元素

// 如果该标签需要当作原生自定义元素则应返回 true。对匹配到的标签,
// Vue 会将其渲染为原生元素而非将其视为一个 Vue 组件来解析。
app.config.compilerOptions.isCustomElement = (tag) => {
  return tag.startsWith('icon_')
}

app 的其他方法

  • 移除/缩短 模版中的空格
app.config.compilerOptions.whitespace = 'condense' // preserve
  • 移除模版中html注释
app.config.compilerOptions.comments = true
  • 生成id的前缀 (v3.5+)
app.config.idPrefix = 'my-app' // 界面自动 my-app-0
// 获取
 const id = useId()
  • 强制在生产环境下跑出错误便于监控
app.config.throwUnhandledErrorInProduction = true
  • 定义一个 异步组件
defineAsyncComponent

在 Vue 3 中,watch、watchEffect 和 computed有不同的用途和行为。以下是它们的主要区别:

watch

  • 用途:用于监听特定的响应式数据或计算属性的变化,并在变化时执行回调函数。

  • 依赖:需要明确指定要监听的依赖项。

  • 执行时机:只有在依赖项发生变化时才会执行回调函数。

  • 示例:

    import { ref, watch } from "vue";
    
    const count = ref(0);
    watch(count, (newValue, oldValue) => {
      console.log(`count 从 ${oldValue} 变为 ${newValue}`);
    });
    

watchEffect

  • 用途:自动追踪回调函数中所有的响应式依赖,并在任何依赖发生变化时重新执行回调函数。

  • 依赖:隐式追踪回调函数中的所有响应式依赖。

  • 执行时机:在组件挂载时立即执行一次,并在任何依赖变化时重新执行。

  • 示例:

    watchEffect(fn, options)
    

    fn: 运行的副作用函数 options: 可以用来调整副作用的刷新时机或调试副作用的依赖。

    import { ref, watchEffect } from "vue";
    
    const count = ref(0);
    
    const add = () => {
      count.value++
    }
    
    //当前的stop是 停止 函数 
    const stop = watchEffect(() => {
      console.log(`count 的值是 ${count.value}`);
    }, {
      flush: 'pre', // 时机  'pre' | 'post' | 'sync' // 默认:'pre'
      onTrack: () => {},
      onTrigger: () => {},
    });
    
    setTimeout(() => {
      stop()
      console.info('停止监听 watchEffect count')
    }, 3000)
    
    // v3.5+
    const { stop, pause, resume } = watchEffect(()=>{})
    // stop 停止 | pause 暂停 | resume 稍后恢复
    

computed

  • 用途:用于声明计算属性,计算属性的值会根据其依赖的响应式数据自动更新。

  • 依赖:隐式追踪计算属性中的所有响应式依赖。

  • 执行时机:只有在依赖发生变化时才会重新计算,并且只有在访问计算属性时才会触发计算。

  • 示例:

    import { ref, computed } from "vue";
    
    const count = ref(0);
    const doubleCount = computed(() => count.value * 2);
    
    console.log(doubleCount.value); // 输出 0
    count.value = 2;
    console.log(doubleCount.value); // 输出 4
    

总结

  • watch:适用于需要精确控制依赖项的场景。
  • watchEffect:适用于需要自动追踪多个依赖项的场景。
  • computed:适用于需要声明计算属性的场景。

追问: watch 要是添加 immediate 作用是不是和 watchEffect 一样的呢?

在 Vue 3 中,watch 添加 immediate 选项后,确实会在初始渲染时立即执行回调函数,这与 watchEffect 的行为类似,但它们之间仍有一些关键区别:

  1. 依赖追踪:

    • watch:需要明确指定要监听的依赖项。即使添加了 immediate 选项,也只会在指定的依赖项变化时执行回调。
    • watchEffect:自动追踪回调函数中所有的响应式依赖,无需明确指定依赖项。任何依赖项变化时都会重新执行回调 ¹²。
  2. 执行时机:

    • watch:在依赖项变化时执行回调。添加 immediate 选项后,会在初始渲染时立即执行一次回调。
    • watchEffect:在组件挂载时立即执行一次,并在任何依赖项变化时重新执行回调 ³。
  3. 使用场景:

    • watch:适用于需要精确控制依赖项的场景,特别是当你只想监听特定的响应式数据或计算属性时。
    • watchEffect:适用于需要自动追踪多个依赖项的场景,特别是当你不确定所有依赖项或希望简化代码时。

示例对比

watch with immediate:

import { ref, watch } from "vue";

const count = ref(0);
watch(
  count,
  (newValue, oldValue) => {
    console.log(`count 从 ${oldValue} 变为 ${newValue}`);
  },
  { immediate: true },
);

watchEffect:

import { ref, watchEffect } from "vue";

const count = ref(0);
watchEffect(() => {
  console.log(`count 的值是 ${count.value}`);
});

总结来说,虽然 watch 添加 immediate 选项后在初始渲染时的行为与 watchEffect 类似,但它们在依赖追踪和使用场景上仍有显著区别。

watchEffect 为什么在初始化就可以执行?

watchEffect 在初始化时立即执行的原因是它的设计初衷是为了自动追踪和响应所有在其回调函数中使用的响应式依赖。以下是一些关键点来解释这一行为:

  1. 自动依赖追踪:watchEffect 会自动追踪回调函数中所有的响应式依赖。这意味着在回调函数第一次执行时,它会记录所有被访问的响应式数据,以便在这些数据发生变化时重新执行回调。

  2. 立即执行:为了确保回调函数能够正确记录所有依赖,watchEffect 在初始化时会立即执行一次。这次执行不仅用于记录依赖,还可以确保在组件挂载时就能响应当前的状态。

  3. 响应式系统:Vue 的响应式系统会在依赖的数据发生变化时触发相应的副作用。通过在初始化时立即执行,watchEffect 能够确保在任何依赖变化时都能及时响应。

以下是一个简单的示例,展示了 watchEffect 如何在初始化时立即执行:

import { ref, watchEffect } from "vue";

const count = ref(0);
watchEffect(() => {
  console.log(`count 的值是 ${count.value}`);
});

onWatcherCleanup

注册一个清理函数,在当前侦听器即将重新运行时执行。只能在 watchEffect 作用函数或 watch 回调函数的同步执行期间调用 (即不能在异步函数的 await 语句之后调用)。

vue3 中 多个 template 的会有什么后果?

  1. 如果多个 <template> 标签中包含相同的变量名,可能会引发作用域冲突,导致意外的行为。
  2. 多个 <template> 标签可能会影响模板编译的效率,增加编译时间。

mixin 弊端 和 替代方案?

  1. 命名冲突:不同的 mixin 可能包含相同的选项名称,导致命名冲突。
  2. 隐式依赖:mixin 可能使用组件中的方法或属性,这会导致代码难以维护和理解。
  3. 代码重复:虽然 mixin 旨在重用代码,但在复杂项目中,可能会导致代码重复和混乱。
  4. 组件耦合:mixin 直接添加选项和属性到组件中,使组件之间的耦合度增加,难以管理

替代方案: Vue3 Composition API

nextTick 的作用?

当更改响应式状态时,最终的DOM更新并不是同步更新,而是有Vue将它们缓存到一个队列中,直到下一个‘tick’才一起执行 这样确保每个组件无论发生多少次状态更改,都执行一次更新。

onErrorCaptured

注册一个钩子,在捕获了后代组件传递的错误时调用。

  1. 组件渲染
  2. 事件处理器
  3. 生命周期钩子
  4. setup() 函数
  5. 侦听器
  6. 自定义指令钩子
  7. 过渡钩子

事件修饰符 (v-on 或者 @click)

  1. stop
  2. prevent
  3. capture
  4. self
  5. once
  6. left
  7. right
  8. middle
  9. passive

vue 中 vdom有哪几部分构成

属性:虚拟节点(VNode)

  1. tag
  2. props
  3. event
  4. children
  5. text
  6. node
  7. key

方法:操作算法

  1. createElement
  2. diff
  3. patch

keep-alive 原理

  1. keep-alive 组件通过内部的缓存机制,保持组件实例在内存中,当组件切换时候,他不会被销毁,而是被缓存起来了
Last Updated:
Contributors: zhanghusheng