<MyInput ref="myInp " :a="a" :b="b" v-model="text">
<template #prepend>
<span>Before</span>
</template>
<template #append>
<span>After</span>
</template>
</MyInput>
<script setup>
import { ref } from 'vue';
import MyInput from './components/MyInput.vue';
const text = ref("Hello vue3");
const myInp = ref(null);
onMounted(()=>{
// 拿到封装组件的示例
console.log(myInp.value);
myInp.value.focus();
})
</script>
<template>
<div class="my-input">
// 获取外层传输过来的数据
<el-input ref="inputRef" v-bind="$attrs">
// 获取外层输出过来的插槽,并动态显示,只需要名字
// 有些插槽属于作用于插槽,是需要要有一些作用于数据需要暴露出去 scopedData
// 常规写法
// <template #prepend="scopedData">
// <slot name="prepend" v-bind="scopedData"></slot>
// </template>
<template v-for="(_,name) in $slots" #[name] = "scopedData">
<slot :name="name" v-bind="scopedData"></slot>
</template>
</el-input>
</div>
</template>
mounted(){
console.log(this.$slots);
console.log(this.$refs.inputRef);
// 进行循环,循环一次,就加到当前的实例里面去
// 这样外层就可以拿到内层的实例
for(const key in this.$refs.inputRef){
this[key] = this.$refs.inputRef[key]
}
}
组件二次封装一般面临三个问题:
1:透传属性和事件
2:透传插槽
3:ref
解决方法:
1:透传属性和事件
利用实例里面的属性,this.$attrs API,接收到外面传过来的所有属性和事件,汇集到这个对象中,页面中直接v-bind绑定即可
注意:这个属性会剔除调那些声明的属性
例:声明了props:['a'] 那么接收到的$attrs中就不会出现a
2:透传插槽
希望把外层定义的插槽,传到UI组件中对应的插槽位置,如果传递插槽为作用域插槽,有作用域数据,那么同样要把数据扔出去;
但是这样挨个写出来会比较麻烦,因为每次想做二次封装的时候,需要去查文档有哪些插槽,一次写完,很麻烦;
还有别人在使用组件的时候,没有传递全部的插槽,但是在封装的时候写了很多插槽,假如说UI组件在内部有自己的逻辑,可能会导致出问题
所以,需要采用动态插槽;
首先需要通过slots获取到外边传递了多少个插槽,传过来是一个对象,对象里面每一个键值对,属性名就对应了插槽的名字,属性值是一个函数
3:ref的透传
希望拿到的东西不再是当前外层使用这个组件的实例,而是内部组件的实例;
可以通过把内部的数据提到当前组件实例去,利用for in 循环
// 进行循环,循环一次,就加到当前的实例里面去
// 这样外层就可以拿到内层的实例
for(const key in this.$refs.inputRef){
this[key] = this.$refs.inputRef[key]
}
借鉴诸多文章,做个个人学习记录