自学内容网 自学内容网

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

vue3 常用函数罗列总结

  1. toRefs

    • 用途
      • 用于将一个响应式对象(例如reactive创建的对象)转换为普通对象,其中每个属性都被转换为ref。这样做的好处是在解构响应式对象时不会丢失响应性。
    • 示例
      • 假设我们有一个reactive对象state,如下:
        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
        import { reactive, toRaw } from 'vue';
        const obj = reactive({
          name: 'John'
        });
        const rawObj = toRaw(obj);
        // 直接操作原始对象,不会触发代理相关的响应式更新
        rawObj.name = 'Jane';
        
    • 注意点
      • 直接操作原始对象可能会导致响应式系统无法正确追踪变化,所以要谨慎使用。一般用于需要将对象传递给外部非响应式的库或者函数的场景。
  3. defineProps

    • 用途
      • 用于在setup函数中定义组件的props。它是一个编译时宏,提供了基于类型的props声明方式,使得组件的props定义更加清晰和类型安全。
    • 示例
      • 在一个Vue组件中:
        <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
        <template>
          <button @click="handleClick">Click me</button>
        </template>
        <script setup>
        const a = 1;
        const handleClick = () => {
          console.log('Clicked');
        };
        defineExpose({
          a,
          handleClick
        });
        </script>
        
      • 父组件可以通过模板引用访问这些暴露的属性和方法:
        <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
        import { ref, watch } from 'vue';
        const count = ref(0);
        watch(count, (newValue, oldValue) => {
          console.log(`Count changed from ${oldValue} to ${newValue}`);
        });
        count.value++;
        
      • 监听一个reactive对象的属性:
        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用途
- 它会立即执行一个函数,并且会自动追踪这个函数内部使用的响应式数据。当这些响应式数据发生变化时,函数会重新执行。

  • 示例
    • 例如:
      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代表单价,计算总价:
        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。例如:
        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
      • 在祖先组件中:
        import { provide } from 'vue';
        const theme = { color: 'blue' };
        provide('theme', theme);
        
    • 定义和用途(inject
      • inject用于在后代组件中注入由祖先组件提供的值。它接受一个参数,即注入的键,返回注入的值。如果没有找到对应的提供值,它可以返回一个默认值。
    • 示例(inject
      • 在后代组件中:
        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)中编写以下代码:
          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文件(文件名可以自定义)。
      • 代码如下:
        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文件中,代码如下:
        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自定义指令,用于在组件加载时自动聚焦到一个输入框元素。
        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自定义指令:
        <template>
          <input type="text" v-autofocus>
        </template>
        
    • 其他指令钩子函数和应用场景
      • 除了mounted钩子函数,还有beforeMountupdatedbeforeUpdateunmounted等钩子函数。
      • 例如,创建一个v - tooltip自定义指令,用于在鼠标悬停时显示一个提示信息。
        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,里面有一个按钮,点击按钮时需要通知父组件:
        <template>
          <button @click="handleClick">Click me</button>
        </template>
        <script setup>
        const emit = defineEmits(['customClick']);
        const handleClick = () => {
          emit('customClick');
        };
        </script>
        
      • 父组件ParentComponent.vue可以监听这个事件:
        <template>
          <ChildComponent @customClick="onChildClick"></ChildComponent>
        </template>
        <script setup>
        const onChildClick = () => {
          console.log('Child component was clicked');
        };
        </script>
        
    • 注意点
      • defineEmits返回的emit函数只能用于发射在参数中定义的事件。它提供了一种类型安全的方式来处理事件发射,有助于避免拼写错误等问题。
  2. defineAsyncComponent

    • 用途
      • 用于定义一个异步组件。在大型应用中,有些组件可能体积较大或者需要异步加载(例如从服务器获取组件代码),defineAsyncComponent可以实现组件的懒加载,从而提高应用的初始加载性能。
    • 示例
      • 假设我们有一个较大的组件LargeComponent.vue,希望异步加载它:
        import { defineAsyncComponent } from 'vue';
        const AsyncLargeComponent = defineAsyncComponent(() =>
          import('./LargeComponent.vue')
        );
        
      • 然后在其他组件中可以像使用普通组件一样使用这个异步组件:
        <template>
          <div>
            <AsyncLargeComponent></AsyncLargeComponent>
          </div>
        </template>
        <script setup>
        // 确保已经正确导入AsyncLargeComponent
        </script>
        
    • 注意点
      • 异步组件在加载过程中可以提供加载状态的反馈,例如显示一个加载动画。可以通过defineAsyncComponent的选项来配置加载状态、加载失败等情况的处理。例如:
        const AsyncLargeComponent = defineAsyncComponent({
          loader: () => import('./LargeComponent.vue'),
          loadingComponent: LoadingComponent,
          errorComponent: ErrorComponent
        });
        
      • 其中LoadingComponent会在异步组件加载过程中显示,ErrorComponent会在异步组件加载失败时显示。
  3. defineComponent

    • 用途
      • 用于定义一个Vue组件,它是一个返回组件选项对象的函数。在使用JavaScript编写组件选项(非<script setup>语法糖)时经常会用到。它可以接收一个对象(组件选项)或者一个返回组件选项对象的函数作为参数。
    • 示例
      • 以下是使用defineComponent定义一个简单组件的示例:
        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。
  • 代码实现
    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
        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
        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. 使用计算属性的组件

    • 功能描述:创建一个组件,有一个输入框用于输入商品价格,还有一个选择框用于选择税率,组件根据输入的价格和选择的税率计算含税价格并显示。
    • 代码实现
      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 }}显示含税价格。

原文地址:https://blog.csdn.net/m0_51244077/article/details/143780116

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!