defineAsyncComponent
异步加载组件的应用场景非常广泛,特别是在多页面应用中,常常需要根据用户需求动态加载不同的页面组件。除此之外,Vue3还支持了使用defineAsyncComponent函数来异步加载指令、插件、模板等其他各种组件。
通常
const HelloWorld=defineComponent(()=>
import('../../components/HelloWorld.vue')
)
高级一点
// with options
const AsyncPopup = defineAsyncComponent({
loader: () => import("../......vue"),
loadingComponent: LoadingComponent, /* 在加载时显示 */
errorComponent: ErrorComponent, /* 显示是否有错误 */
delay: 1000, /* 在显示加载组件之前延迟毫秒 */
timeout: 3000 /* 这个毫秒之后的超时 */
})
defineComponent
一般是在ts或者tsx文件中使用
在这种情况下,我们需要defineComponent来帮我们做内部的一些options的提示
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Test',
props:{
data: String,
},
template:''
setup(props, context){
// props.data
// context.attrs context.slots context.emit
return ...
},
...
})
defineCustomElement
参考官网
默认情况下,Vue 会将任何非原生的 HTML 标签优先当作 Vue 组件处理,而将“渲染一个自定义元素”作为后备选项。这会在开发时导致 Vue 抛出一个“解析组件失败”的警告。要让 Vue 知晓特定元素应该被视为自定义元素并跳过组件解析
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
template: {
compilerOptions: {
// 将所有带短横线的标签名都视为自定义元素
isCustomElement: (tag) => tag.includes('-')
}
}
})
]
}
接收的参数和 defineComponent 完全相同,但是他还多了styles参数
import { defineCustomElement } from 'vue'
const MyVueElement = defineCustomElement({
...
template: `<div>{{title}}</div>`,
// defineCustomElement 特有的:注入进 shadow root 的 CSS,行内样式
styles: [`
div {
color: red
}
`]
})
// 注册自定义元素
// 注册之后,所有此页面中的 `<my-vue-element>` 标签
// 都会被升级
customElements.define('my-vue-element', MyVueElement)
export default MyVueElement
defineSSRCustomElement
.....官网api都没搜到,推测跟上面那个差不多但是是服务器端的
defineEmits和defineProps
defineEmits类似于组件上的@click、@change ......等固有方法(子组件需要一个或多个自定义方法,父组件提供给他),可以根据子组件提供的值修改父组件
defineProps类似于组件上的一些参数,如class,name.......,他不能直接修改(props.abc=abc会报错)
.............................子组件.......................................
<script setup lang="ts">
import { ref } from 'vue'
//定义组件参数
const props = defineProps({
str: {
type: String,
default: '123',
reqiured:true
}
})
const sstr = ref(props.str)
//一般是这样写
// const emit = defineEmits([
// 'add1'
// ])
//但是这样可以定义该函数返回类型
const emit = defineEmits<{ (e: 'add1'): void, }>()
const changeValue = () => {
emit('add1')
}
</script>
<template>
<button @click="changeValue">{{ sstr }}</button>
</template>
............................父组件..............................
<script setup lang="ts">
import ZuJianChuanZhi from "../../components/ZuJianChuanZhi.vue"
import { ref } from "vue"
//上级组件的传参
import { useRoute } from "vue-router";
const route = useRoute()
const btnValue = ref(route.query.str ? route.query.str.toString() : '没有参数传递')
const addStr = () => {
console.log('使用了emit');
}
</script>
<template>
<ZuJianChuanZhi :str="btnValue" @add1="addStr" />
</template>
defineExpose
可以暴露子组件的属性和方法,让父组件用ref去使用
子组件
/**
* defineExpose
*/
const count = ref(0);
function increment() {
count.value++;
}
defineExpose({
count,
increment,
})
父组件
<script setup lang="ts">
import ZuJianChuanZhi from "../../components/ZuJianChuanZhi.vue"
import { ref } from "vue"
const addStr = () => {
console.log('使用了emit');
}
const childRef = ref()
//这里不要慌直接赋值childRef.value.count,加载组件时,子组件还没创建好,要报错,
//也不要直接把childRef.value.count绑定上去,原因和上面一样
const count = ref(0)
const addCount = () => {
if (childRef.value) {
childRef.value.increment()
//这里单独使count.value++无法改变子组件中count的值
count.value = childRef.value.count
}
}
</script>
<template>
<ZuJianChuanZhi ref="childRef" />
<button @click="addCount">count:{{ count }}</button>
</template>
defineOptions
vue3.3及以上才能用
在选项式api中组件有name等一些属性,其他属性props,emits等都有相应的define方法,这个也有
<script setup lang="ts">
defineOptions({
name: '组件名称'
inheritAttrs: false, // 组件标签上的属性是否透传
customOptions: {
/* 其他配置 */
}
})
</script>
defineModel
使用props时,在父组件改变传入的值,子组件改变不不了,这时候就要用到defineModel了
子组件
<script setup lang="ts">
import { ref } from 'vue'
/**
* defineProps
*/
const props = defineProps({
str: {
type: String,
default: '123',
}
})
const sstr = ref(props.str)
/**
* defineModel
*/
const model = defineModel()
console.log(model);
</script>
<template>
<button @click="changeValue">{{ sstr }}</button>
<input type="text" v-model="model" width="20px">
</template>
父组件
<script setup lang="ts">
import ZuJianChuanZhi from "../../components/ZuJianChuanZhi.vue"
import { ref, } from "vue"
import { useRoute } from "vue-router";
const route = useRoute()
const btnValue = ref(route.query.str ? route.query.str.toString() : '没有参数传递')
// 这里就简单把input的值加在按钮参数后面
const childRef = ref()
const count = ref(0)
const inputValue = ref('132')
const cli = () => {
inputValue.value = (inputValue.value == '123' ? '321' : '123')
btnValue.value = (inputValue.value == '123' ? '321' : '123')//没有变化
}
</script>
<template>
<button @click="cli">click</button>
<ZuJianChuanZhi :str="btnValue" v-model="inputValue" />
</template>
---------------------------------------------------
他还可以定义参数的类型,名字等,用法和defineProps一样
参考这里
defineSlots
仅限与ts使用,vue3.3+
我们可以使用 defineSlots 自己定义插槽的类型。这个宏在简单的组件中几乎用不到,但对于一些复杂的组件非常有用,尤其是这个特性与泛型组件一起使用。或是在 Volar 无法正确地推测出类型时,我们可以手动指定
<script setup lang="ts">
const slots = defineSlots<{
// key > default 是插槽名称
// 值类型是插槽函数
// 函数的第一个TS对象类型参数是插槽期望接收的 props 的TS类型
// 返回值类型目前被忽略,可以是 any,但官方说将来可能会利用它来检查插槽内容。
default(props: { msg: string }): any
}>()
</script>