文章目录
-
- [vue3 常用函数罗列总结](#vue3 常用函数罗列总结)
- [vue3 中批量注册组件](#vue3 中批量注册组件)
- [vue3 自定义指令应用](#vue3 自定义指令应用)
- [define 应用补充](#define 应用补充)
- [defineComponent 不同场景应用实例](#defineComponent 不同场景应用实例)
vue3 常用函数罗列总结
-
toRefs
-
用途 :
- 用于将一个响应式对象(例如
reactive
创建的对象)转换为普通对象,其中每个属性都被转换为ref
。这样做的好处是在解构响应式对象时不会丢失响应性。
- 用于将一个响应式对象(例如
-
示例 :
-
假设我们有一个
reactive
对象state
,如下:javascriptimport { 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++;
-
-
注意点 :
- 主要用于在需要解构响应式对象的场景下,确保属性仍然能够触发响应式更新。
-
-
toRaw
-
用途 :
- 可以获取一个由
reactive
或者readonly
创建的代理对象的原始对象。在某些情况下,当你不想通过代理访问对象,而是直接操作原始对象时很有用。
- 可以获取一个由
-
示例 :
-
例如,有一个
reactive
对象obj
:javascriptimport { reactive, toRaw } from 'vue'; const obj = reactive({ name: 'John' }); const rawObj = toRaw(obj); // 直接操作原始对象,不会触发代理相关的响应式更新 rawObj.name = 'Jane';
-
-
注意点 :
- 直接操作原始对象可能会导致响应式系统无法正确追踪变化,所以要谨慎使用。一般用于需要将对象传递给外部非响应式的库或者函数的场景。
-
-
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的值。如果需要修改,应该通过向父组件发射事件来请求修改。
- 它只能在
-
-
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
可以更好地控制组件的接口,避免不必要的属性和方法暴露给父组件。
- 合理使用
-
-
watch
-
用途 :
- 用于监听一个或多个响应式数据的变化,并在数据变化时执行一个副作用函数。它可以用于响应式数据的深度监听、异步操作等场景。
-
示例 :
-
监听一个
ref
:javascriptimport { ref, watch } from 'vue'; const count = ref(0); watch(count, (newValue, oldValue) => { console.log(`Count changed from ${oldValue} to ${newValue}`); }); count.value++;
-
监听一个
reactive
对象的属性:javascriptimport { 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
用途 :
- 它会立即执行一个函数,并且会自动追踪这个函数内部使用的响应式数据。当这些响应式数据发生变化时,函数会重新执行。
-
示例 :
-
例如:
javascriptimport { ref, watchEffect } from 'vue'; const count = ref(0); watchEffect(() => { console.log(`Count is now ${count.value}`); }); count.value++;
-
-
注意点 :
- 与
watch
不同,watchEffect
不需要手动指定要监听的数据,它会自动根据函数内部使用的响应式数据进行追踪。但是这也可能导致一些意外的重新执行情况,所以要注意函数内部的逻辑和副作用。
- 与
-
computed
-
定义和用途 :
computed
用于创建计算属性。它接受一个函数作为参数,这个函数会根据它所依赖的响应式数据自动重新计算结果。计算属性具有缓存机制,只有当它所依赖的响应式数据发生变化时,才会重新计算。
-
示例 :
-
假设有一个
ref
代表数量和一个ref
代表单价,计算总价:javascriptimport { 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
-
-
注意点 :
-
计算属性默认是只读的。如果要创建可写的计算属性,可以传递一个包含
get
和set
函数的对象给computed
。例如:javascriptconst fullName = computed({ get: () => firstName.value + ' ' + lastName.value, set: (newValue) => { const names = newValue.split(' '); firstName.value = names[0]; lastName.value = names[1]; } });
-
-
-
inject
和provide
-
定义和用途(
provide
) :provide
用于在祖先组件中提供一个值,使得后代组件可以访问这个值。它接受两个参数,第一个参数是注入的键(可以是Symbol
或者String
),第二个参数是要提供的值。
-
示例(
provide
) :-
在祖先组件中:
javascriptimport { provide } from 'vue'; const theme = { color: 'blue' }; provide('theme', theme);
-
-
定义和用途(
inject
) :inject
用于在后代组件中注入由祖先组件提供的值。它接受一个参数,即注入的键,返回注入的值。如果没有找到对应的提供值,它可以返回一个默认值。
-
示例(
inject
) :-
在后代组件中:
javascriptimport { inject } from 'vue'; const theme = inject('theme', { color: 'black' }); console.log(theme.color);
-
-
注意点 :
provide
和inject
主要用于跨组件层级的数据传递。但要注意过度使用可能会导致数据来源不清晰,所以要谨慎使用,并且最好在文档中明确组件之间的这种依赖关系。
-
vue3 中批量注册组件
-
Vue 3全局组件批量注册(根据目录文件夹读取注册,Webpack环境)
- 目录结构准备
- 假设我们有一个
components
文件夹,里面存放着多个Vue组件,组件文件以.vue
为后缀。例如,components
文件夹下有Button.vue
、Input.vue
、Card.vue
等组件。
- 假设我们有一个
- 批量注册函数实现
-
创建一个函数来读取指定目录下的组件并进行批量注册。可以使用
require.context
(在基于Webpack等构建工具的环境下)来实现。-
在
main.js
或者一个专门的工具文件(如registerComponents.js
)中编写以下代码:javascriptimport { 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等支持这种语法的构建工具,可能需要使用其他方式来读取文件目录和组件。 - 组件名的提取方式是基于文件名的简单转换。如果组件文件名不符合常规命名规范或者有特殊要求,可能需要调整组件名提取的逻辑。
- 这种方式依赖于构建工具对
- 目录结构准备
-
Vue 3 全局组件批量注册 vite 环境
- 目录结构设置
- 假设在
src
目录下有一个components
文件夹,该文件夹下包含了所有需要全局注册的组件,组件文件以.vue
为后缀。例如有Button.vue
、Input.vue
等组件。
- 假设在
- 创建批量注册函数
-
在
src
目录下创建一个registerGlobalComponents.js
文件(文件名可以自定义)。 -
代码如下:
javascriptimport { 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
是组件模块的默认导出(通常是组件本身)。
- 在Vite环境中,
-
- 在主文件中应用注册函数
-
在
main.js
文件中,代码如下:javascriptimport { 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 自定义指令应用
-
Vue 3自定义指令实例应用
-
创建自定义指令
-
自定义指令可以在
main.js
或者一个专门的指令文件(如directives.js
)中创建。 -
例如,创建一个
v - autofocus
自定义指令,用于在组件加载时自动聚焦到一个输入框元素。javascriptimport { 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
钩子函数,还有beforeMount
、updated
、beforeUpdate
、unmounted
等钩子函数。 -
例如,创建一个
v - tooltip
自定义指令,用于在鼠标悬停时显示一个提示信息。javascriptapp.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
钩子函数中,为元素添加mouseenter
和mouseleave
事件监听器。当鼠标进入元素时,显示提示元素,并根据元素的位置设置提示元素的位置。当鼠标离开元素时,隐藏提示元素。 - 在
unmounted
钩子函数中,当指令从元素上解绑时,将提示元素从文档中移除。
- 在
-
-
注意事项
- 在自定义指令中操作DOM元素时,要注意浏览器的兼容性和性能。例如,频繁地创建和销毁DOM元素或者频繁地计算元素位置可能会导致性能问题。
- 指令钩子函数中的参数(如
el
和binding
)提供了有关指令绑定的重要信息,要正确理解和使用这些参数来实现所需的功能。binding
参数包含指令的值、表达式、参数等信息。
-
define 应用补充
-
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
函数只能用于发射在参数中定义的事件。它提供了一种类型安全的方式来处理事件发射,有助于避免拼写错误等问题。
-
-
defineAsyncComponent
-
用途 :
- 用于定义一个异步组件。在大型应用中,有些组件可能体积较大或者需要异步加载(例如从服务器获取组件代码),
defineAsyncComponent
可以实现组件的懒加载,从而提高应用的初始加载性能。
- 用于定义一个异步组件。在大型应用中,有些组件可能体积较大或者需要异步加载(例如从服务器获取组件代码),
-
示例 :
-
假设我们有一个较大的组件
LargeComponent.vue
,希望异步加载它:javascriptimport { defineAsyncComponent } from 'vue'; const AsyncLargeComponent = defineAsyncComponent(() => import('./LargeComponent.vue') );
-
然后在其他组件中可以像使用普通组件一样使用这个异步组件:
html<template> <div> <AsyncLargeComponent></AsyncLargeComponent> </div> </template> <script setup> // 确保已经正确导入AsyncLargeComponent </script>
-
-
注意点 :
-
异步组件在加载过程中可以提供加载状态的反馈,例如显示一个加载动画。可以通过
defineAsyncComponent
的选项来配置加载状态、加载失败等情况的处理。例如:javascriptconst AsyncLargeComponent = defineAsyncComponent({ loader: () => import('./LargeComponent.vue'), loadingComponent: LoadingComponent, errorComponent: ErrorComponent });
-
其中
LoadingComponent
会在异步组件加载过程中显示,ErrorComponent
会在异步组件加载失败时显示。
-
-
-
defineComponent
-
用途 :
- 用于定义一个Vue组件,它是一个返回组件选项对象的函数。在使用JavaScript编写组件选项(非
<script setup>
语法糖)时经常会用到。它可以接收一个对象(组件选项)或者一个返回组件选项对象的函数作为参数。
- 用于定义一个Vue组件,它是一个返回组件选项对象的函数。在使用JavaScript编写组件选项(非
-
示例 :
-
以下是使用
defineComponent
定义一个简单组件的示例:javascriptimport { 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
可以很好地处理组件选项的合并和类型推导。它也有助于代码的组织结构清晰,特别是在处理复杂组件选项时。
- 当使用组合式API(
-
defineComponent 不同场景应用实例
- 简单的计数器组件
-
功能描述:创建一个具有一个按钮和一个显示计数数字的组件,每次点击按钮,计数数字加1。
-
代码实现
javascriptimport { 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。最后将count
和increment
返回,这样它们就可以在模板中使用。 - 模板部分使用了双大括号
{``{ count }}
来显示count
的值,并且将按钮的@click
事件绑定到increment
函数,当按钮被点击时,count
的值就会增加。
- 在
-
带有父子组件通信的组件
-
功能描述:创建一个父组件包含一个子组件,父组件向子组件传递一个初始计数,子组件有一个按钮用于增加计数,并且将更新后的计数发送回父组件。
-
代码实现
-
子组件
ChildComponent.vue
javascriptimport { 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
javascriptimport { 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
函数。
- 子组件 :在
-
-
使用计算属性的组件
-
功能描述:创建一个组件,有一个输入框用于输入商品价格,还有一个选择框用于选择税率,组件根据输入的价格和选择的税率计算含税价格并显示。
-
代码实现
javascriptimport { 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
函数创建。它根据price
和selectedTaxRate
的值计算含税价格。每当price
或者selectedTaxRate
的值发生变化时,totalPrice
会自动重新计算。- 在模板中,使用
v - model
指令将输入框的值绑定到price
,将选择框的值绑定到selectedTaxRate
,并使用双大括号{``{ totalPrice }}
显示含税价格。
- 在
-