vue3 中那些常用 靠copy 的内置函数

文章目录

    • [vue3 常用函数罗列总结](#vue3 常用函数罗列总结)
    • [vue3 中批量注册组件](#vue3 中批量注册组件)
    • [vue3 自定义指令应用](#vue3 自定义指令应用)
    • [define 应用补充](#define 应用补充)
    • [defineComponent 不同场景应用实例](#defineComponent 不同场景应用实例)

vue3 常用函数罗列总结

  1. toRefs

    • 用途

      • 用于将一个响应式对象(例如reactive创建的对象)转换为普通对象,其中每个属性都被转换为ref。这样做的好处是在解构响应式对象时不会丢失响应性。
    • 示例

      • 假设我们有一个reactive对象state,如下:

        javascript 复制代码
        import { reactive, toRefs } from 'vue';
        const state = reactive({
          count: 0,
          message: 'Hello'
        });
        // 如果直接解构,会丢失响应性
        // const { count, message } = state;
        const { count, message } = toRefs(state);
        // 现在count和message是ref,可以保持响应性
        console.log(count.value); 
        count.value++;
    • 注意点

      • 主要用于在需要解构响应式对象的场景下,确保属性仍然能够触发响应式更新。
  2. toRaw

    • 用途

      • 可以获取一个由reactive或者readonly创建的代理对象的原始对象。在某些情况下,当你不想通过代理访问对象,而是直接操作原始对象时很有用。
    • 示例

      • 例如,有一个reactive对象obj

        javascript 复制代码
        import { reactive, toRaw } from 'vue';
        const obj = reactive({
          name: 'John'
        });
        const rawObj = toRaw(obj);
        // 直接操作原始对象,不会触发代理相关的响应式更新
        rawObj.name = 'Jane';
    • 注意点

      • 直接操作原始对象可能会导致响应式系统无法正确追踪变化,所以要谨慎使用。一般用于需要将对象传递给外部非响应式的库或者函数的场景。
  3. defineProps

    • 用途

      • 用于在setup函数中定义组件的props。它是一个编译时宏,提供了基于类型的props声明方式,使得组件的props定义更加清晰和类型安全。
    • 示例

      • 在一个Vue组件中:

        html 复制代码
        <template>
          <div>{{ props.message }}</div>
        </template>
        <script setup>
        const props = defineProps({
          message: String
        });
        </script>
    • 注意点

      • 它只能在<script setup>中使用。并且defineProps返回的对象是只读的,不能直接修改props的值。如果需要修改,应该通过向父组件发射事件来请求修改。
  4. defineExpose

    • 用途

      • 用于在<script setup>组件中明确地指定组件向外暴露的属性和方法。默认情况下,在<script setup>中的变量和函数不会自动暴露给父组件,defineExpose可以控制暴露的内容。
    • 示例

      • 假设我们有一个子组件ChildComponent

        html 复制代码
        <template>
          <button @click="handleClick">Click me</button>
        </template>
        <script setup>
        const a = 1;
        const handleClick = () => {
          console.log('Clicked');
        };
        defineExpose({
          a,
          handleClick
        });
        </script>
      • 父组件可以通过模板引用访问这些暴露的属性和方法:

        html 复制代码
        <template>
          <ChildComponent ref="childRef"></ChildComponent>
          <button @click="accessChildProperties">Access Child</button>
        </template>
        <script setup>
        import { ref } from 'vue';
        const childRef = ref(null);
        const accessChildProperties = () => {
          console.log(childRef.value.a);
          childRef.value.handleClick();
        };
        </script>
    • 注意点

      • 合理使用defineExpose可以更好地控制组件的接口,避免不必要的属性和方法暴露给父组件。
  5. watch

    • 用途

      • 用于监听一个或多个响应式数据的变化,并在数据变化时执行一个副作用函数。它可以用于响应式数据的深度监听、异步操作等场景。
    • 示例

      • 监听一个ref

        javascript 复制代码
        import { ref, watch } from 'vue';
        const count = ref(0);
        watch(count, (newValue, oldValue) => {
          console.log(`Count changed from ${oldValue} to ${newValue}`);
        });
        count.value++;
      • 监听一个reactive对象的属性:

        javascript 复制代码
        import { reactive, watch } from 'vue';
        const state = reactive({
          name: 'John'
        });
        watch(() => state.name, (newValue, oldValue) => {
          console.log(`Name changed from ${oldValue} to ${newValue}`);
        });
        state.name = 'Jane';
    • 注意点

      • watch可以设置深度监听(deep选项)、立即执行(immediate选项)等配置。同时,当监听多个数据源时,要注意合理处理每个数据源变化时的逻辑。

6.watchEffect用途

  • 它会立即执行一个函数,并且会自动追踪这个函数内部使用的响应式数据。当这些响应式数据发生变化时,函数会重新执行。
  • 示例

    • 例如:

      javascript 复制代码
      import { ref, watchEffect } from 'vue';
      const count = ref(0);
      watchEffect(() => {
        console.log(`Count is now ${count.value}`);
      });
      count.value++;
  • 注意点

    • watch不同,watchEffect不需要手动指定要监听的数据,它会自动根据函数内部使用的响应式数据进行追踪。但是这也可能导致一些意外的重新执行情况,所以要注意函数内部的逻辑和副作用。
  1. computed

    • 定义和用途

      • computed用于创建计算属性。它接受一个函数作为参数,这个函数会根据它所依赖的响应式数据自动重新计算结果。计算属性具有缓存机制,只有当它所依赖的响应式数据发生变化时,才会重新计算。
    • 示例

      • 假设有一个ref代表数量和一个ref代表单价,计算总价:

        javascript 复制代码
        import { ref, computed } from 'vue';
        const quantity = ref(2);
        const price = ref(5);
        const total = computed(() => quantity.value * price.value);
        console.log(total.value); // 10
        quantity.value++;
        console.log(total.value); // 15
    • 注意点

      • 计算属性默认是只读的。如果要创建可写的计算属性,可以传递一个包含getset函数的对象给computed。例如:

        javascript 复制代码
        const fullName = computed({
          get: () => firstName.value + ' ' + lastName.value,
          set: (newValue) => {
            const names = newValue.split(' ');
            firstName.value = names[0];
            lastName.value = names[1];
          }
        });
  2. injectprovide

    • 定义和用途(provide

      • provide用于在祖先组件中提供一个值,使得后代组件可以访问这个值。它接受两个参数,第一个参数是注入的键(可以是Symbol或者String),第二个参数是要提供的值。
    • 示例(provide

      • 在祖先组件中:

        javascript 复制代码
        import { provide } from 'vue';
        const theme = { color: 'blue' };
        provide('theme', theme);
    • 定义和用途(inject

      • inject用于在后代组件中注入由祖先组件提供的值。它接受一个参数,即注入的键,返回注入的值。如果没有找到对应的提供值,它可以返回一个默认值。
    • 示例(inject

      • 在后代组件中:

        javascript 复制代码
        import { inject } from 'vue';
        const theme = inject('theme', { color: 'black' });
        console.log(theme.color);
    • 注意点

      • provideinject主要用于跨组件层级的数据传递。但要注意过度使用可能会导致数据来源不清晰,所以要谨慎使用,并且最好在文档中明确组件之间的这种依赖关系。

vue3 中批量注册组件

  1. Vue 3全局组件批量注册(根据目录文件夹读取注册,Webpack环境)

    • 目录结构准备
      • 假设我们有一个components文件夹,里面存放着多个Vue组件,组件文件以.vue为后缀。例如,components文件夹下有Button.vueInput.vueCard.vue等组件。
    • 批量注册函数实现
      • 创建一个函数来读取指定目录下的组件并进行批量注册。可以使用require.context(在基于Webpack等构建工具的环境下)来实现。

        • main.js或者一个专门的工具文件(如registerComponents.js)中编写以下代码:

          javascript 复制代码
          import { createApp } from 'vue';
          const app = createApp(App);
          // 创建一个函数用于批量注册组件
          const registerGlobalComponents = () => {
            // 使用require.context读取组件目录
            const requireComponent = require.context
            ('./components', true, /\.vue$/);
            requireComponent.keys().forEach((fileName) => {
              // 获取组件配置
              const componentConfig = requireComponent(fileName);
              // 提取组件名,将文件名转换为组件名(首字母大写)
              const componentName = fileName.split('/').pop()
              .replace(/\.\w+$/, '').
              replace(/^\w/, (c) => c.toUpperCase());
              // 注册组件
              app.component(componentName, componentConfig.default 
              || componentConfig);
            });
          };
          registerGlobalComponents();
          app.mount('#app');
      • 解释:

        • require.context函数用于创建一个上下文,它接受三个参数。第一个参数是要搜索的目录('./components'),第二个参数true表示是否搜索子目录,第三个参数/\.vue$/是一个正则表达式,用于匹配文件名(只匹配.vue文件)。
        • requireComponent.keys()返回所有匹配的文件路径数组。对于每个文件路径fileName,通过requireComponent(fileName)获取组件的配置。
        • 提取组件名时,首先使用split('/')分割文件路径,获取文件名,然后使用replace方法去掉文件后缀.vue,最后将文件名的首字母转换为大写,作为组件名。
        • 使用app.component方法将组件注册到应用中,其中componentName是组件名,componentConfig.default || componentConfig是组件配置(在ES模块中,组件通常是通过export default导出的,所以先尝试获取default属性)。
    • 注意事项
      • 这种方式依赖于构建工具对require.context的支持。如果不使用Webpack等支持这种语法的构建工具,可能需要使用其他方式来读取文件目录和组件。
      • 组件名的提取方式是基于文件名的简单转换。如果组件文件名不符合常规命名规范或者有特殊要求,可能需要调整组件名提取的逻辑。
  2. Vue 3 全局组件批量注册 vite 环境

    • 目录结构设置
      • 假设在src目录下有一个components文件夹,该文件夹下包含了所有需要全局注册的组件,组件文件以.vue为后缀。例如有Button.vueInput.vue等组件。
    • 创建批量注册函数
      • src目录下创建一个registerGlobalComponents.js文件(文件名可以自定义)。

      • 代码如下:

        javascript 复制代码
        import { App } from 'vue';
        // 自动导入组件目录下的所有.vue组件
        const requireComponent = import.meta.globEager('./components/*.vue');
        export default function registerGlobalComponents(app: App) {
          for (const path in requireComponent) {
            const componentConfig = requireComponent[path];
            // 获取组件名,将文件名转换为组件名(首字母大写)
            const componentName = path.split('/').pop().replace(/\.\w+$/, '')
            .replace(/^\w/, (c) => c.toUpperCase());
            app.component(componentName, componentConfig.default);
          }
        }
      • 解释:

        • 在Vite环境中,import.meta.globEager用于同步地导入指定目录下的模块。这里它会导入./components/*.vue目录下的所有.vue组件,返回一个对象,键是文件路径,值是组件模块。
        • 然后通过遍历这个对象,对于每个组件模块,提取组件名(将文件名转换为组件名,首字母大写)。
        • 最后使用app.component方法将组件注册到App应用中,其中componentName是组件名,componentConfig.default是组件模块的默认导出(通常是组件本身)。
    • 在主文件中应用注册函数
      • main.js文件中,代码如下:

        javascript 复制代码
        import { createApp } from 'vue';
        import App from './App.vue';
        import registerGlobalComponents from './registerGlobalComponents';
        const app = createApp(App);
        registerGlobalComponents(app);
        app.mount('#app');
      • 解释:

        • 首先导入createApp函数用于创建应用,App组件作为根组件,以及刚刚创建的registerGlobalComponents函数。
        • 创建app应用实例后,调用registerGlobalComponents函数并传入app实例,完成组件的批量注册。
        • 最后将应用挂载到DOM中的#app元素上。

vue3 自定义指令应用

  1. Vue 3自定义指令实例应用

    • 创建自定义指令

      • 自定义指令可以在main.js或者一个专门的指令文件(如directives.js)中创建。

      • 例如,创建一个v - autofocus自定义指令,用于在组件加载时自动聚焦到一个输入框元素。

        javascript 复制代码
        import { createApp } from 'vue';
        const app = createApp(App);
        app.directive('autofocus', {
          mounted(el) {
            el.focus();
          }
        });
        app.mount('#app');
      • 解释:

        • app.directive方法用于创建自定义指令。第一个参数'autofocus'是指令名称,第二个参数是一个包含指令钩子函数的对象。
        • mounted钩子函数中,el是指令所绑定的DOM元素,通过el.focus()方法使元素获得焦点。
    • 在模板中使用自定义指令

      • 假设我们有一个Input.vue组件,在其模板中使用v - autofocus自定义指令:

        html 复制代码
        <template>
          <input type="text" v-autofocus>
        </template>
    • 其他指令钩子函数和应用场景

      • 除了mounted钩子函数,还有beforeMountupdatedbeforeUpdateunmounted等钩子函数。

      • 例如,创建一个v - tooltip自定义指令,用于在鼠标悬停时显示一个提示信息。

        javascript 复制代码
        app.directive('tooltip', {
          beforeMount(el, binding) {
            // 创建一个提示元素
            const tooltip = document.createElement('div');
            tooltip.textContent = binding.value;
            tooltip.style.position = 'absolute';
            tooltip.style.backgroundColor = 'gray';
            tooltip.style.color = 'white';
            tooltip.style.padding = '5px';
            tooltip.style.borderRadius = '3px';
            tooltip.style.zIndex = '10';
            // 将提示元素添加到文档中,但先隐藏
            document.body.appendChild(tooltip);
            el._tooltip = tooltip;
          },
          mounted(el, binding) {
            el.addEventListener('mouseenter', () => {
              const tooltip = el._tooltip;
              const rect = el.getBoundingClientRect();
              tooltip.style.display = 'block';
              tooltip.style.left = rect.left + 'px';
              tooltip.style.top = rect.bottom + 'px';
            });
            el.addEventListener('mouseleave', () => {
              const tooltip = el._tooltip;
              tooltip.style.display = 'none';
            });
          },
          unmounted(el) {
            const tooltip = el._tooltip;
            document.body.removeChild(tooltip);
          }
        });
      • 解释:

        • beforeMount钩子函数中,创建一个用于显示提示信息的div元素,设置其样式,并将其添加到文档中,但先隐藏起来。同时,将这个提示元素存储在el._tooltip中,方便后续使用。
        • mounted钩子函数中,为元素添加mouseentermouseleave事件监听器。当鼠标进入元素时,显示提示元素,并根据元素的位置设置提示元素的位置。当鼠标离开元素时,隐藏提示元素。
        • unmounted钩子函数中,当指令从元素上解绑时,将提示元素从文档中移除。
    • 注意事项

      • 在自定义指令中操作DOM元素时,要注意浏览器的兼容性和性能。例如,频繁地创建和销毁DOM元素或者频繁地计算元素位置可能会导致性能问题。
      • 指令钩子函数中的参数(如elbinding)提供了有关指令绑定的重要信息,要正确理解和使用这些参数来实现所需的功能。binding参数包含指令的值、表达式、参数等信息。

define 应用补充

  1. defineEmits

    • 用途

      • <script setup>语法糖中,用于定义组件向外发射(emit)的事件。这使得组件可以和父组件进行通信,当子组件内部发生某些操作时,可以通过发射事件的方式通知父组件。
    • 示例

      • 假设有一个子组件ChildComponent.vue,里面有一个按钮,点击按钮时需要通知父组件:

        html 复制代码
        <template>
          <button @click="handleClick">Click me</button>
        </template>
        <script setup>
        const emit = defineEmits(['customClick']);
        const handleClick = () => {
          emit('customClick');
        };
        </script>
      • 父组件ParentComponent.vue可以监听这个事件:

        html 复制代码
        <template>
          <ChildComponent @customClick="onChildClick"></ChildComponent>
        </template>
        <script setup>
        const onChildClick = () => {
          console.log('Child component was clicked');
        };
        </script>
    • 注意点

      • defineEmits返回的emit函数只能用于发射在参数中定义的事件。它提供了一种类型安全的方式来处理事件发射,有助于避免拼写错误等问题。
  2. defineAsyncComponent

    • 用途

      • 用于定义一个异步组件。在大型应用中,有些组件可能体积较大或者需要异步加载(例如从服务器获取组件代码),defineAsyncComponent可以实现组件的懒加载,从而提高应用的初始加载性能。
    • 示例

      • 假设我们有一个较大的组件LargeComponent.vue,希望异步加载它:

        javascript 复制代码
        import { defineAsyncComponent } from 'vue';
        const AsyncLargeComponent = defineAsyncComponent(() =>
          import('./LargeComponent.vue')
        );
      • 然后在其他组件中可以像使用普通组件一样使用这个异步组件:

        html 复制代码
        <template>
          <div>
            <AsyncLargeComponent></AsyncLargeComponent>
          </div>
        </template>
        <script setup>
        // 确保已经正确导入AsyncLargeComponent
        </script>
    • 注意点

      • 异步组件在加载过程中可以提供加载状态的反馈,例如显示一个加载动画。可以通过defineAsyncComponent的选项来配置加载状态、加载失败等情况的处理。例如:

        javascript 复制代码
        const AsyncLargeComponent = defineAsyncComponent({
          loader: () => import('./LargeComponent.vue'),
          loadingComponent: LoadingComponent,
          errorComponent: ErrorComponent
        });
      • 其中LoadingComponent会在异步组件加载过程中显示,ErrorComponent会在异步组件加载失败时显示。

  3. defineComponent

    • 用途

      • 用于定义一个Vue组件,它是一个返回组件选项对象的函数。在使用JavaScript编写组件选项(非<script setup>语法糖)时经常会用到。它可以接收一个对象(组件选项)或者一个返回组件选项对象的函数作为参数。
    • 示例

      • 以下是使用defineComponent定义一个简单组件的示例:

        javascript 复制代码
        import { defineComponent, ref } from 'vue';
        const MyComponent = defineComponent({
          setup() {
            const count = ref(0);
            const increment = () => {
              count.value++;
            };
            return {
              count,
              increment
            };
          },
          template: `
            <div>
              <p>Count: {{ count }}</p>
              <button @click="increment">Increment</button>
            </div>
          `
        });
    • 注意点

      • 当使用组合式API(setup函数)和选项式API混合编写组件时,defineComponent可以很好地处理组件选项的合并和类型推导。它也有助于代码的组织结构清晰,特别是在处理复杂组件选项时。

defineComponent 不同场景应用实例

  1. 简单的计数器组件
  • 功能描述:创建一个具有一个按钮和一个显示计数数字的组件,每次点击按钮,计数数字加1。

  • 代码实现

    javascript 复制代码
    import { defineComponent, ref } from 'vue';
    export default defineComponent({
      setup() {
        // 创建一个响应式的ref,初始值为0
        const count = ref(0);
        const increment = () => {
          count.value++;
        };
        return {
          count,
          increment
        };
      },
      template: `
        <div>
          <p>Count: {{ count }}</p>
          <button @click="increment">Increment</button>
        </div>
      `
    });
  • 解释

    • setup函数中,首先使用ref创建了一个响应式数据count,初始值为0。然后定义了一个函数increment,用于将count的值加1。最后将countincrement返回,这样它们就可以在模板中使用。
    • 模板部分使用了双大括号{``{ count }}来显示count的值,并且将按钮的@click事件绑定到increment函数,当按钮被点击时,count的值就会增加。
  1. 带有父子组件通信的组件

    • 功能描述:创建一个父组件包含一个子组件,父组件向子组件传递一个初始计数,子组件有一个按钮用于增加计数,并且将更新后的计数发送回父组件。

    • 代码实现

      • 子组件ChildComponent.vue

        javascript 复制代码
        import { defineComponent, defineEmits, ref } from 'vue';
        export default defineComponent({
          setup(props) {
            const emit = defineEmits(['updateCount']);
            const increment = () => {
              emit('updateCount', props.count + 1);
            };
            return {
              increment
            };
          },
          props: {
            count: Number
          },
          template: `
            <div>
              <button @click="increment">Increment in Child</button>
            </div>
          `
        });
      • 父组件ParentComponent.vue

        javascript 复制代码
        import { defineComponent, ref } from 'vue';
        import ChildComponent from './ChildComponent.vue';
        export default defineComponent({
          setup() {
            const count = ref(0);
            const handleUpdateCount = (newCount) => {
              count.value = newCount;
            };
            return {
              count,
              handleUpdateCount
            };
          },
          template: `
            <div>
              <p>Parent Count: {{ count }}</p>
              <ChildComponent :count="count" @updateCount="handleUpdateCount">
              </ChildComponent>
            </div>
          `
        });
    • 解释

      • 子组件 :在setup函数中,通过defineEmits定义了一个名为updateCount的事件。increment函数用于发射这个事件,并将更新后的计数(props.count + 1)作为参数传递。props中定义了count属性,用于接收父组件传递过来的计数。
      • 父组件 :在setup函数中,count是一个ref,用于存储计数。handleUpdateCount函数用于接收子组件发射的updateCount事件,并更新count的值。在模板中,将count传递给子组件的count属性,并且监听子组件的updateCount事件,当事件触发时,调用handleUpdateCount函数。
  2. 使用计算属性的组件

    • 功能描述:创建一个组件,有一个输入框用于输入商品价格,还有一个选择框用于选择税率,组件根据输入的价格和选择的税率计算含税价格并显示。

    • 代码实现

      javascript 复制代码
      import { defineComponent, ref, computed } from 'vue';
      export default defineComponent({
        setup() {
          const price = ref(0);
          const taxRateOptions = [
            { label: '0%', value: 0 },
            { label: '5%', value: 0.05 },
            { label: '10%', value: 0.1 }
          ];
          const selectedTaxRate = ref(taxRateOptions[0].value);
          const totalPrice = computed(() => {
            return price.value * (1 + selectedTaxRate.value);
          });
          return {
            price,
            taxRateOptions,
            selectedTaxRate,
            totalPrice
          };
        },
        template: `
          <div>
            <input v - model="price" type="number" placeholder="Price">
            <select v - model="selectedTaxRate">
              <option v - for="option in taxRateOptions"
               :value="option.value">{{ option.label }}</option>
            </select>
            <p>Total Price with Tax: {{ totalPrice }}</p>
          </div>
        `
      });
    • 解释

      • setup函数中,price是一个ref,用于存储商品价格。taxRateOptions是一个包含税率选项的数组。selectedTaxRate是一个ref,用于存储用户选择的税率。
      • totalPrice是一个计算属性,通过computed函数创建。它根据priceselectedTaxRate的值计算含税价格。每当price或者selectedTaxRate的值发生变化时,totalPrice会自动重新计算。
      • 在模板中,使用v - model指令将输入框的值绑定到price,将选择框的值绑定到selectedTaxRate,并使用双大括号{``{ totalPrice }}显示含税价格。
相关推荐
寻找沙漠的人19 分钟前
前端知识补充—CSS
前端·css
GISer_Jing31 分钟前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_7482455232 分钟前
吉利前端、AI面试
前端·面试·职场和发展
理想不理想v44 分钟前
webpack最基础的配置
前端·webpack·node.js
pubuzhixing1 小时前
开源白板新方案:Plait 同时支持 Angular 和 React 啦!
前端·开源·github
2401_857600951 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600951 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL1 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据1 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
轻口味1 小时前
Vue.js 核心概念:模板、指令、数据绑定
vue.js