组件不满足需求,要对当前组件再次封装,会遇到以下一些问题:
1、原组件的Attributes怎么处理原组件属性可以通过透传
$attrs,获取父组件的属性
<el-input ref="childInputRef" v-bind="$attrs"></el-input>
2、原组件的插槽怎么设置
通过$slots获取当前组件所有的插槽对象,通过遍历添加到原组件插槽
子组件:searchInput.vue
<el-input ref="childInputRef" v-bind="$attrs">
<template v-for="(value, name) in $slots" #[name]>
<slot :name="name"></slot>
</template>
</el-input>
父组件
<SearchInput >
<template #append">
<el-button>Search</el-button>
</template>
</SearchInput>
效果:
具名作用域插槽
子组件:searchInput.vue
<el-input ref="childInputRef" v-bind="$attrs">
<template v-for="(value, name) in $slots" #[name]>
<slot :name="name" :slotData="slotData">></slot>
</template>
</el-input>
...
....
const slotData = reactive({
msg: 'aaaa'
})
父组件
<SearchInput>
<template #append="{slotData}">
{{ slotData.msg }}
<el-button>Search</el-button>
</template>
</SearchInput>
效果:
3、原组件的ref方法调用
将原组件的提供的方法加入到当前组件中
子组件:searchInput.vue
<el-input ref="childInputRef" v-bind="$attrs"></el-input>
<script setup lang="ts">
import { useAttrs, ref, onMounted, reactive, useSlots } from 'vue'
const childInputRef = ref()
const options = reactive<{[key: string]: any}>({})
const slotData = reactive({
msg: 'aaaa'
})
onMounted(() => {
const entries = Object.entries(childInputRef?.value)
console.log('entries:', entries)
for (const [key, value] of entries) {
if (!value || typeof value !== 'function') {
continue
}
options[key] = value
}
})
父组件:
<template>
<div>
<SearchInput
ref="searchInput"
>
</SearchInput>
<el-button @click="changeFocus">Focus</el-button>
</div>
</template>
<script setup lang="ts">
const searchInput = ref()
function changeFocus() {
searchInput.value.focus()
}
</script>
完整代码:
子组件:searchInput.vue
<template>
<div>
<el-input ref="childInputRef" v-bind="$attrs">
<template v-for="(value, name) in slots" #[name]>
<slot :name="name" :slotData="slotData"></slot>
</template>
</el-input>
</div>
</template>
<script setup lang="ts">
import { useAttrs, ref, onMounted, reactive, useSlots } from 'vue'
// const attrs = useAttrs()
const slots = useSlots()
const childInputRef = ref()
const options = reactive<{[key: string]: any}>({})
const slotData = reactive({
msg: 'aaaa'
})
onMounted(() => {
const entries = Object.entries(childInputRef?.value)
console.log('entries:', entries)
for (const [key, value] of entries) {
if (!value || typeof value !== 'function') {
continue
}
options[key] = value
}
})
defineExpose(options)
</script>
父组件:index.vue
<template>
<div>
<SearchInput
ref="searchInput"
v-model="searchForm.keyword"
placeholder="请输入"
active-value
show-password
clearable
@change="handleChange">
<template #append="{slotData}">
{{ slotData.msg }}
<el-button>Search</el-button>
</template>
</SearchInput>
<el-button @click="changeFocus">Focus</el-button>
</div>
</template>
<script setup lang="ts">
import SearchInput from './views/layout/components/searchInput.vue'
import { onMounted, reactive, ref, toRef, toRefs, getCurrentInstance } from 'vue';
const searchInput = ref()
const searchForm = reactive({
keyword: ''
})
function changeFocus() {
console.log('keyword:', searchForm.keyword)
searchInput.value.focus()
}
function handleChange(v: string) {
console.log('input:', v)
}
</script>
<style lang="scss" scoped>
</style>