likes
comments
collection
share

掌握精心挑选的 24 个 Vue3 知识点,金三银四不用愁|详细讲解

作者站长头像
站长
· 阅读数 13

前言

又到金三银四的时候了,虽然现在外面的就业环境不太乐观,但是,我相信好大一部分人也已经开始蠢蠢欲动了(也有可能是领了大礼包)。不管怎样,只要咱们做到了心中有货,那就可以完全不慌。

知识点

下面是我这几天熬夜精心整理的 24 个知识点,每个知识点不仅有详细讲解还有代码示例,包你满意。

1. filter

在 Vue 3 中,没有了全局的 Vue.filter 方法。取而代之的是在应用程序实例中,通过 config.globalProperties.$filters 对象定义过滤器。

下面将展示如何使用 $filters 对象定义和使用过滤器:

import { createApp } from 'vue';

const app = createApp({
  data() {
    return {
      message: 'hello world'
    };
  },
  // 定义一个过滤器
  created() {
    app.config.globalProperties.$filters.capitalize = function (value) {
      if (!value) return '';
      value = value.toString();
      return value.charAt(0).toUpperCase() + value.slice(1);
    };
  },
  template: `
    <div>{{ message | capitalize }}</div>
  `
});

app.mount('#app');

在上面的代码中,我们首先使用 createApp 函数创建了一个应用程序实例 app。然后,在实例的 created 钩子中,我们使用 $filters 对象定义了一个名为 capitalize 的过滤器。该过滤器将字符串的第一个字母转换为大写字母,并返回新的字符串。

最后,在模板中,我们通过管道符号 | 使用 capitalize 过滤器对 message 数据进行过滤,将其第一个字母转换为大写字母。

需要注意的是,在 Vue 3 中,过滤器是一个普通的函数,而不是像 Vue 2 中那样是一个对象。因此,我们可以使用普通的函数语法定义过滤器,也可以使用箭头函数语法定义过滤器。

2. mixin

在 Vue 3 中,使用 mixin 可以将一个或多个选项混入到组件中,相当于是将多个组件共用的逻辑提取出来,避免代码重复。与 Vue 2 中的 mixin 不同,Vue 3 中的 mixin 只能包含一组选项,而不是一个完整的组件定义。

使用 mixin 有以下几种方式:

  1. 全局 mixin

可以通过 app.mixin()createApp().mixin() 在全局注册一个 mixin,注册之后,每个组件都会混入该 mixin 中的选项。

下面是一个全局 mixin 的示例代码:

const app = createApp({})
app.mixin({
  data() {
    return {
      message: 'Hello Vue 3'
    }
  },
  created() {
    console.log('mixin created')
  }
})
  1. 局部 mixin

除了全局 mixin 外,还可以在组件中使用局部 mixin。通过 mixins 选项来混入一个或多个 mixin。

下面是一个局部 mixin 的示例代码:

const myMixin = {
  data() {
    return {
      message: 'Hello Vue 3'
    }
  },
  created() {
    console.log('mixin created')
  }
}

const app = createApp({
  mixins: [myMixin],
  created() {
    console.log('component created')
  }
})

注意:当组件和 mixin 中有同名的选项时,组件选项会覆盖 mixin 中的选项。

在 Vue 2 中,mixins 是创建可重用组件逻辑的主要方式。尽管在 Vue 3 中保留了 mixins 支持,但对于组件间的逻辑复用,Composition API 是现在更推荐的方式。

3. directive

在 Vue 3 中,我们可以使用 directive 函数来自定义指令,可以用于在模板中添加一些特殊的行为和样式,将其绑定到 DOM 元素上,并在元素的生命周期中执行。

下面演示了如何使用 directive 函数定义一个自定义指令:

<template>
  <div v-my-directive="'red'">Hello, world!</div>
</template>

<script>
import { directive } from 'vue';

const myDirective = directive('my-directive', {
  mounted(el, binding) {
    el.style.color = binding.value;
  }
});

export default {
  directives: {
    myDirective
  }
};
</script>

在上面的代码中,我们定义了一个名为 myDirective 的自定义指令。该指令在元素的 mounted 生命周期钩子中会将元素的颜色设置为指令参数中传入的颜色值。

随后将 myDirective 指令注册到 directives 选项中。在模板中,我们可以通过 v-my-directive 指令来绑定自定义指令,并将指令参数设置为 'red'

需要注意的是,在定义自定义指令时,我们需要使用 directive 函数,并将其传入指令的名称和配置对象。配置对象中可以包含一些钩子函数,用于在指令的生命周期中执行一些操作。另外,在组件中使用自定义指令时,需要将其注册到 directives 选项中。

在指令的配置对象中,可配置钩子函数包括 beforeMountmountedbeforeUpdateupdatedbeforeUnmountunmounted。这些钩子函数分别在指令的生命周期中不同的阶段执行,可以用于实现各种不同的功能和行为。

4. watchEffect

watchEffect 用于响应式地追踪一个函数执行时用到的响应式数据,并在这些响应式数据变更时重新运行该函数。这个 API 返回一个无论在何时都会自动执行的 effect 函数,其会自动追踪响应式数据的变更。

下面是一个使用 watchEffect 的示例:

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const count = ref(0);

    // 监听 count 的变化,每次 count 变化时输出变化后的值
    watchEffect(() => {
      console.log(`count is ${count.value}`);
    });

    function increment() {
      count.value++;
    }

    return {
      count,
      increment,
    };
  },
};
</script>

上面的示例中,我们通过 watchEffect 监听了 count 的变化,每次 count 变化时都会自动运行我们传给 watchEffect 的函数,函数中可以访问到 count.value,并在控制台输出变化后的值。

需要注意的是,由于 watchEffect 自动追踪响应式数据的变化,所以在函数中只要用到了响应式数据,该函数就会被追踪。因此,建议只在必要时使用 watchEffect,并在函数中只使用必要的响应式数据,避免无用的性能消耗。

5. watchPostEffect

watchPostEffect 用于在 Vue 的渲染完成后执行一个副作用。它类似于watchEffect,但是会在组件的渲染周期中最后一个被调用。

下面是一个使用watchPostEffect的示例代码:

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
import { ref, watchPostEffect } from 'vue'

export default {
  setup() {
    const count = ref(0)

    const increment = () => {
      count.value++
    }

    watchPostEffect(() => {
      console.log('render finished')
    })

    return {
      count,
      increment
    }
  }
}
</script>

在这个示例中,我们定义了一个名为 count 的响应式变量,并在点击按钮时对其进行递增。在 setup() 函数中,我们使用 watchPostEffect 来执行一个副作用,即在组件的渲染完成后,在控制台中输出一条消息。这样,每次组件重新渲染完成后,都会在控制台中看到一条 "render finished" 的消息。

值得注意的是,watchPostEffect 只能在 setup() 函数中使用,不能在组件的模板中使用。

使用 watchPostEffect 的主要场景是当你需要在组件的渲染周期中的最后一步执行一些副作用时。这可以帮助你在一些特殊情况下处理组件的状态或者处理 DOM 节点的变化。

6. watchSyncEffect

watchSyncEffect,它和 watchEffect 的作用类似,都是用来观测数据变化并执行副作用函数。不同的是,watchSyncEffect可以在同步更新之前立即执行副作用函数,这意味着副作用函数会在数据更新前执行。

这个 API 可以用于一些需要在数据更新前执行副作用函数的场景,比如某些需要提前清除缓存的操作。

下面是一个使用watchSyncEffect的示例代码:

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
import { watchSyncEffect, ref } from 'vue';

export default {
  setup() {
    const count = ref(0);

    watchSyncEffect(() => {
      console.log('Current count:', count.value);
      // do some synchronous work
    });

    function increment() {
      count.value++;
    }

    return {
      count,
      increment,
    };
  },
};
</script>

上面的代码中,我们定义了一个 count 变量,每次点击按钮都会使其自增。同时,我们使用 watchSyncEffect 来观测 count 变量的变化,并执行副作用函数,副作用函数会在数据更新前立即执行。

需要注意的是,watchSyncEffect 仅在 Vue3.2 及以上版本中可用。

7. effectScope

Vue 3 中的 effectScope API 允许开发人员创建可嵌套的 effect 块,以将副作用与其引用的响应式变量绑定在一起。当使用 effectScope 时,只有在其所属的范围内更改的变量才会触发作用于该范围内的 effect,这对于减少不必要的重复计算和提高性能非常有用。

以下是一个简单的示例,展示如何在组件中使用 effectScope

<template>
  <div>
    <button @click="incrementCount">Increment</button>
    <p>Count: {{ count }}</p>
    <p>Doubled Count: {{ doubledCount }}</p>
  </div>
</template>

<script>
import { effectScope, reactive, watch } from 'vue';

export default {
  setup() {
    const scope = effectScope();
    const state = reactive({
      count: 0,
    });

    // 声明 count 副作用
    scope.run(() => {
      watch(() => state.count, () => {
        console.log('Count changed:', state.count);
      });
    });

    // 声明 doubledCount 副作用
    const doubledCount = scope.run(() => {
      return computed(() => state.count * 2);
    });

    // 点击按钮时增加计数器
    function incrementCount() {
      state.count++;
    }

    return {
      count: state.count,
      doubledCount,
      incrementCount,
    };
  },
};
</script>

在此示例中,我们创建了一个 effectScope,并在其中定义了两个副作用:一个用于监视计数器的变化,另一个用于计算计数器的两倍。由于这两个副作用都是在 effectScope 中创建的,因此只有当 count 发生变化时,才会触发对应的副作用。

使用 effectScope 可以更好地管理副作用的范围和生命周期,以提高代码的可读性和性能。

8. globalProperties

在 Vue 3 中,可以使用 app.config.globalProperties 属性将全局属性和方法添加到 Vue 实例中。这意味着,所有的组件都可以访问到这些全局属性和方法,无需再进行引入或者挂载。

下面将展示如何使用 app.config.globalProperties 添加全局属性和方法:

import { createApp } from 'vue';

const app = createApp({});

// 添加全局属性
app.config.globalProperties.$globalProp = 'hello';

// 添加全局方法
app.config.globalProperties.$globalMethod = function (message) {
  console.log(message);
};

app.mount('#app');

在上面的代码中,我们首先使用 createApp 函数创建了一个 Vue 应用程序实例 app。然后,我们使用 app.config.globalProperties 属性向应用程序实例中添加了一个全局属性 $globalProp,以及一个全局方法 $globalMethod

下面是使用示例:

export default {
  mounted() {
    console.log(this.$globalProp);
    this.$globalMethod('word');
  }
};

在这个示例中,我们在组件的 mounted 钩子中调用了全局方法 $globalMethod,并将 $globalProp$globalMethod 参数输出到控制台中。

需要注意的是,虽然可以使用 app.config.globalProperties 向应用程序实例中添加全局属性和方法,但这种方式并不推荐。这种方式容易导致命名冲突和意外覆盖,建议使用插件或者 mixin 的方式来添加全局属性和方法。

9. performance

Vue3 提供了 app.config.performance 用于开启性能追踪,可以帮助开发者发现应用中的性能问题。

通过设置 app.config.performancetrue,可以开启性能追踪。当开启性能追踪后,Vue3 会在开发者工具控制台中输出有关组件渲染和更新的性能指标信息,包括渲染次数、渲染耗时、DOM 更新次数等等。

下面是一个示例代码,展示了如何在 Vue3 中开启性能追踪:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 开启性能追踪
app.config.performance = true

app.mount('#app')

在开发者工具控制台中,可以看到有关性能追踪的详细信息。例如,可以看到每个组件渲染的时间、更新的次数等等。这些信息可以帮助开发者识别应用中的性能瓶颈,并针对性地进行优化。

注意:这个 API 仅在开发模式和支持 performance.mark API 的浏览器中工作。

10. getCurrentInstance

Vue 3中引入了getCurrentInstance函数,用于获取当前组件实例。这个函数可以在组件的各种钩子函数和方法中使用。

import { getCurrentInstance } from 'vue'

export default {
  setup() {
    const instance = getCurrentInstance()
    const { $router } = instance.app.config.globalProperties

    return {
      goBack() {
        $router.go(-1)
      }
    }
  }
}

在这个示例中,我们在组件的setup函数中使用了getCurrentInstance函数获取当前组件实例,并从实例的全局属性中获取$router对象。然后,我们定义了一个goBack方法,用于返回上一个页面。

11. computed 的 ref 选项

Vue 3 中的 computed 函数引入了 ref 选项,用于控制计算属性是否被视为一个响应式引用。以下是一个示例代码:

import { computed } from 'vue'

const count = ref(0)

const doubleCount = computed(() => count.value * 2, { ref: true })

在这个示例中,我们使用 computed 函数创建了一个计算属性 doubleCount,并使用 ref 选项将其视为一个响应式引用,以便在模板中直接使用。

12. reactive 的 shallow 选项

Vue 3中的 reactive 函数引入了 shallow 选项,用于控制对象的响应式深度。以下是一个示例代码:

import { reactive } from 'vue'

const obj = reactive({
  a: {
    b: {
      c: 1
    }
  }
})

const shallowObj = reactive({
  a: {
    b: {
      c: 1
    }
  }
}, { shallow: true })

在这个示例中,我们使用 reactive 函数创建了两个响应式对象 objshallowObj,并使用 shallow 选项将 shallowObj 的响应式深度限制为1,即只追踪第一层属性的变化。

13. defineAsyncComponent

在 Vue 3 中,可以使用 defineAsyncComponent 函数定义异步组件,从而优化应用程序的性能,减少初始加载时间。这种方式可以将组件代码拆分成多个文件,在需要时再进行动态加载,而不是一次性加载所有组件代码。

下面是一个示例代码,展示如何使用 defineAsyncComponent 函数定义异步组件:

import { defineAsyncComponent } from 'vue';

const AsyncComponent = defineAsyncComponent({
  // 异步加载组件
  loader: () => import('./AsyncComponent.vue'),
  // 加载组件时显示的占位符
  loadingComponent: LoadingComponent,
  // 加载失败时显示的占位符
  errorComponent: ErrorComponent,
  // 组件加载超时时间(默认值为 3000 毫秒)
  timeout: 5000
});

export default {
  components: {
    AsyncComponent
  },
  template: `
    <div>
      <AsyncComponent />
    </div>
  `
};

在上面的代码中,我们首先使用 defineAsyncComponent 函数定义了一个异步组件 AsyncComponent,该组件通过动态加载 ./AsyncComponent.vue 文件来获取组件代码。

同时,我们还指定了 loadingComponenterrorComponent,分别表示组件加载时和加载失败时显示的占位符。在组件加载完成前,会先显示 loadingComponent,加载失败时则会显示 errorComponent

在组件中,我们可以像使用普通组件一样使用 AsyncComponent,如 <AsyncComponent />

需要注意的是,异步组件只有在首次使用时才会进行加载,之后再次使用时将会从缓存中读取组件代码,因此建议在需要时再进行定义。

总的来说,defineAsyncComponent 函数为 Vue 3 提供了更加灵活的组件定义方式,可以提升应用程序的性能和用户体验。

14. 利用 toRefs 函数解构 props

在Vue 3.0中,props 是响应式的,不能使用 ES6 结构,因为解构会消除 props 的响应性。

如果需要解构 props,可以在 setup 函数中使用 toRefs 函数来完成此操作:

import { toRefs } from 'vue';
 
export default {
  setup(props){
    const { title } = toRefs(props);
    console.log(title.value);
  }
}

如果 title 是可选的 props, 则传入的 props 中可能没有 title,这种情况下就需要 toRef 来代替它

import { toRef } from 'vue';

export default {
  setup(props){
    const title = toRef(props, 'title');
    console.log(title.value);
  }
}

15. Teleport

Vue 3 中的 Teleport 组件可以用来在组件中渲染到指定的 DOM 节点中。它的作用是将组件的内容从父级 DOM 树中转移到指定的 DOM 节点中,以达到更灵活的布局效果。

使用 Teleport 组件的代码示例:

<template>
  <div>
    <button @click="showModal = true">Open Modal</button>
    <teleport to="#modal">
      <div v-if="showModal" class="modal">
        <h2>Modal Title</h2>
        <p>Modal Content</p>
        <button @click="showModal = false">Close Modal</button>
      </div>
    </teleport>
  </div>
  <div id="modal"></div>
</template>

<script>
export default {
  data() {
    return {
      showModal: false
    }
  }
}
</script>

在上面的示例中,我们通过 Teleport 组件将模态框的内容渲染到 id="modal" 的 DOM 节点中。当用户点击 "Open Modal" 按钮时,会根据 v-if 指令的条件判断,决定是否渲染模态框的内容。而这个内容会被包裹在 Teleport 组件中,指定其渲染到 id="modal" 的 DOM 节点中。

需要注意的是,为了让 Teleport 组件能够正确地工作,我们需要将目标节点(即上例中的 id="modal")提前定义好,并保证其在组件渲染时已经存在。否则,Teleport 组件可能会出现意想不到的问题。

在实际开发中,Teleport 组件通常被用来实现模态框、下拉菜单、提示框等需要在组件之外渲染的场景,以达到更灵活的布局效果。

16. Suspense

Vue 3 中的 Suspense 组件是用来处理异步组件加载时的占位符和加载状态的。它可以将一个异步组件的加载状态封装成一个占位符组件,并在异步组件加载完成后自动替换占位符组件,从而提高用户体验和页面性能。

使用 Suspense 组件的代码示例:

<template>
  <div>
    <suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <template #fallback>
        <div>Loading...</div>
      </template>
    </suspense>
  </div>
</template>

<script>
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue'))

export default {
  components: {
    AsyncComponent
  }
}
</script>

在上面的示例中,我们使用 defineAsyncComponent 函数创建一个异步组件,并将其作为默认插槽的内容传递给 Suspense 组件。在异步组件加载完成前,Suspense 组件会渲染 fallback 插槽中的占位符内容(即 "Loading..."),等异步组件加载完成后再将其渲染到页面中。

需要注意的是,为了让 Suspense 组件能够正确地工作,异步组件必须返回一个包含 default 导出的对象,该对象中的 default 属性必须是一个组件选项对象。

在实际开发中,Suspense 组件通常被用来处理异步组件的加载状态,以提高用户体验和页面性能。同时,我们还可以利用 Suspense 组件的嵌套功能,实现更复杂的异步组件加载逻辑。

17. Fragment

在 Vue 3 中,我们可以使用 Fragment 来包裹多个根节点而不需要添加一个无意义的父级节点。Vue 3 还提供了 Fragment 的简写(空标签对 <> ),使得在模板中更加简洁。

以下是一个示例代码,其中一个组件使用 Fragment 简写来包裹两个根节点:

<template>
  <>
    <h1>这是标题</h1>
    <p>这是内容</p>
  </>
</template>

上面代码中,<h1><p> 是两个根节点,使用 Fragment 简写可以将它们包装在一起,而不需要再添加一个无意义的父级节点。

另外需要注意的是,如果你使用了 Fragment 简写,必须要使用 Vue 3.2.0 及以上的版本才能编译通过。如果你使用的是较老版本的 Vue 3,可以使用 <!-- --> 注释标签作为类似的替代方案。

18. 新的 v-model 语法

在 Vue 3 中,v-model 指令支持新的语法糖,可以将组件的 value 属性和 input 事件绑定到一个名为 modelValuepropsupdate:modelValue 的事件上。

下面是一个简单的示例代码:

<template>
  <MyComponent v-model:modelValue="message"></MyComponent>
</template>

<script>
import MyComponent from './MyComponent.vue'

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

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

<script>
export default {
  props: {
    modelValue: {
      type: String,
      required: true
    }
  }
}
</script>

在父组件中,我们使用 v-model 语法来将 message 绑定到自定义组件的 modelValue 属性上。在自定义组件中,我们使用 :value="modelValue"modelValue 的值绑定到输入框上,并通过 @input="$emit('update:modelValue', $event.target.value)" 监听输入框的输入事件,将新的值传递回父组件。

注意,我们在自定义组件的 props 中定义了一个名为 modelValue 的属性,这个属性的类型为 String,并且是必需的。这是因为父组件使用 v-model 语法时会自动向自定义组件传递一个 modelValue 的值,而我们需要在自定义组件中声明这个属性以避免出现警告。

19. 静态节点提升

Vue 3 的静态节点提升是一个新特性,旨在通过将静态节点从模板中提取出来并在渲染时重用,从而提高渲染性能。在 Vue 3 中,如果一个节点被确定为静态节点,它将在编译时被提取出来,并在渲染时被重复使用,这样可以减少重复渲染静态内容的时间。

在 Vue 3 中,静态节点可以使用 v-once 指令标记为静态。例如:

<template>
  <div>
    <h1 v-once>{{ title }}</h1>
    <span>hxkj.vip</span>
    <p>{{ content }}</p>
    <div>{{ staticText }}</div>
    <div>{{ dynamicText }}</div>
  </div>
</template>

在上面的示例中,<h1> 标签使用了 v-once 指令,<span> 标签为静态文本内容,因此它们被确定为静态节点,并在渲染时被重复使用。而 <p> 标签和包含动态数据的 <div> 标签则被认为是动态节点,每次渲染都会重新计算。

另外,Vue 3 还提供了一个新的编译选项 hoistStatic,用于控制是否将静态节点提升。默认情况下,hoistStatic 是开启的,也就是说静态节点会被提升。如果你需要禁用静态节点提升,可以在创建 Vue 实例时传入 compilerOptions 选项:

import { createApp } from 'vue'

const app = createApp({
  // ...
})

app.config.compilerOptions = {
  hoistStatic: false
}

总之,静态节点提升是 Vue 3 的一个重要特性,可以显著提高渲染性能。在开发过程中,如果确定该节点里的内容不会被改变,应该尽可能地标记为静态节点,以便 Vue 3 可以对它们进行提升。

20. provide 与 inject

在 Vue 3 中,我们可以使用 provideinject 两个函数来实现父组件向子组件传递数据,而无需一层层地通过 props 传递。

具体来说,provide 函数用于在父组件中定义要传递的数据,而 inject 函数用于在子组件中获取这些数据。下面是一个简单的示例代码:

// 父组件 MyParent.vue
<template>
  <div>
    <h2>Parent Component</h2>
    <p>Message: {{ message }}</p>
    <MyChild></MyChild>
  </div>
</template>

<script>
import { provide } from 'vue'
import MyChild from './MyChild.vue'

export default {
  components: { MyChild },
  setup() {
    const message = 'Hello from parent component'
    provide('message', message)
  }
}
</script>

// 子组件 MyChild.vue
<template>
  <div>
    <h2>Child Component</h2>
    <p>Message: {{ message }}</p>
  </div>
</template>

<script>
import { inject } from 'vue'

export default {
  setup() {
    const message = inject('message')
    return { message }
  }
}
</script>

在父组件中,我们使用 provide 函数将要传递的数据(这里是一个字符串 'Hello from parent component')定义为 message,并将其传递给子组件。在子组件中,我们使用 inject 函数获取父组件传递过来的 message,并将其赋值给一个本地变量。在模板中,我们可以通过 {{ message }} 来使用这个变量。

注意,我们在父组件中使用 provide('message', message) 来定义要传递的数据。第一个参数是一个字符串,用于指定这个数据的名称,可以随意定义,但需要和子组件中的 inject 函数中的参数名保持一致。第二个参数是实际的数据。

在子组件中,我们使用 inject('message') 来获取父组件中的数据。这里的参数也是一个字符串,表示要获取的数据的名称。注意,如果父组件没有定义这个数据,或者这个数据还没有被 provide,那么子组件中的 inject 函数会返回 undefined。因此,我们需要在子组件中对返回值进行判断。

21. isVNode

在Vue3中,isVNode是一个用于检查对象是否为虚拟节点的函数。它返回一个布尔值,如果对象是虚拟节点则返回true,否则返回false

以下是一个示例代码:

import { createVNode, isVNode } from 'vue';

const vnode = createVNode('div', { class: 'container' }, [
  createVNode('p', null, 'This is a paragraph.'),
]);

console.log(isVNode(vnode)); // true
console.log(isVNode({})); // false

在上面的代码中,我们使用createVNode创建了一个虚拟节点,然后使用isVNode函数检查该节点是否是虚拟节点。因为该节点是虚拟节点,所以输出结果是true

然后我们传递一个空对象给isVNode函数进行检查,由于它不是虚拟节点,输出结果是false

乍一看,貌似没啥用处,其实他主要用于在开发Vue3插件时判断某个对象是否为虚拟节点。在Vue3中,虚拟节点是通过 createVNode 等函数创建的对象,用于描述组件树的结构和状态,它们不直接对应DOM元素,而是经过Vue的渲染器处理后生成真实的DOM节点。

除了在插件开发中,isVNode 函数也可以用于调试或测试中,可以帮助我们判断某个对象是否是虚拟节点。

以下是一个在插件开发中使用 isVNode 函数的示例代码:

export default {
  install(app) {
    app.directive('my-directive', {
      mounted(el, binding, vnode) {
        if (!isVNode(vnode)) {
          console.warn('The provided argument is not a VNode!');
          return;
        }
        // TODO: do something with the vnode
      }
    });
  }
}

在上面的代码中,我们在自定义指令的mounted钩子函数中使用isVNode函数判断传入的vnode参数是否为虚拟节点。如果不是虚拟节点,则输出一个警告信息,并直接返回。如果是虚拟节点,则可以根据实际需求做一些处理。

总的来说,isVNode函数在Vue3的开发过程中使用频率不如其他API高,但是在某些场景下也是非常有用的。

22. markRaw

在 Vue 3 中,当需要将一个对象标记为“不可响应”(即不被 Vue 响应式系统追踪)时,可以使用 markRaw 函数。

具体来说,当使用 markRaw 函数标记一个对象时,这个对象将不再具有响应式特性,它的任何属性更新都不会触发组件的重新渲染,也不会触发任何依赖于该属性的副作用函数。

下面是一个示例代码:

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="incrementCount">Increment</button>
  </div>
</template>

<script>
import { markRaw, reactive } from 'vue';

export default {
  setup() {
    const state = reactive({
      count: markRaw(0) // 将 count 标记为不可响应
    });

    const incrementCount = () => {
      state.count++;
    };

    return {
      count: state.count,
      incrementCount
    };
  }
};
</script>

在上面的代码中,我们将 count 标记为不可响应,这样每次更新 count 时不会触发组件的重新渲染。这在一些场景下非常有用,比如需要保存一个大量数据的对象,但这些数据只需要在初始化时被响应式追踪一次即可,后续更新不需要触发重新渲染。

23. <script setup>

<script setup> 是 Vue 3 中的一个新特性,它是一个更加简洁、优雅、可读性更高的 SFC(Single File Component)语法糖,可以让我们更加方便地编写组件逻辑代码。下面我们来看一下 <script setup> 的具体用法和示例代码。

首先,需要注意的是,<script setup> 的代码必须在 <template> 后面,用于声明组件的 props、data、computed 等选项,示例代码如下:

<template>
  <div>{{ count }}</div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
</script>

在上面的代码中,我们使用了 import 语句引入了 ref 方法,然后使用 const 声明了一个名为 count 的响应式数据,初始值为 0。接着,我们定义了一个名为 increment 的函数,用于将 count 的值加 1。

需要注意的是,我们使用 ref 方法创建的 count 变量可以直接在模板中使用,而不需要像 Vue 2 中那样需要写成 count.value

此外,<script setup> 也支持声明 props,示例代码如下:

phpCopy code
<template>
  <div>{{ message }}</div>
</template>

<script setup>
props: {
  message: String
}
</script>

在上面的代码中,我们使用 props 声明了一个名为 message 的字符串类型的 prop。这样,我们就可以在模板中使用 message 变量了。

除了支持声明 props 和数据,<script setup> 还支持声明 computed、methods、watch 等选项,示例代码如下:

<template>
  <div>{{ count }}</div>
</template>

<script setup>
import { ref, computed } from 'vue'

const count = ref(0)

const doubleCount = computed(() => count.value * 2)

function increment() {
  count.value++
}

watch(() => count.value, (newValue, oldValue) => {
  console.log(`count 变化了,新值为 ${newValue},旧值为 ${oldValue}`)
})
</script>

在上面的代码中,我们声明了一个名为 doubleCount 的计算属性,它的值是 count 的值乘以 2。我们还声明了一个名为 increment 的方法,它用于将 count 的值加 1。最后,我们使用 watch 监听了 count 的变化,并在控制台打印了变化的值。

总之,<script setup> 语法糖可以让我们更加方便地编写组件逻辑代码,让代码变得更加简洁、易读、易维护。

24. CSS 中的 v-bind()

单文件组件的 <style> 标签支持使用 v-bind CSS 函数将 CSS 的值链接到动态的组件状态:

<template>
  <div class="text">hello</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

<style>
.text {
  color: v-bind(color);
}
</style>

这个语法同样也适用于 <script setup>,且支持 JavaScript 表达式 (需要用引号包裹起来):

<script setup>
const theme = {
  color: 'red'
}
</script>

<template>
  <p>hello</p>
</template>

<style scoped>
p {
  color: v-bind('theme.color');
}
</style>

实际的值会被编译成哈希化的 CSS 自定义属性,因此 CSS 本身仍然是静态的。自定义属性会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式地更新。

结语

不知各位爽否?

不妨来个一键三连(点赞 + 关注 + 收藏),让我也爽一下。

作者:HashTang