Vue3组件二次封装的小技巧
点击关注公众号,“技术干货”及时达!
刚才在 b 站学了两个二次封装组件的小技巧 (b 站果然是个学习平台)
双向数据绑定向子组件传递插槽获取子组件的 ref我们使用 vite 初始化一个 vue、ts 的项目,然后安装下 element-plus
下边开始展示
双向数据绑定我们以 input 组件作为例子
双向数据绑定的原理及实现想必大家已经烂熟于心了直接看官网吧!
子组件接受一个 modelValue 的 prop, 通过 emit 触发 update:modelValue 事件完成数据的更新
父组件直接 v-model="xxxx"
嫌麻烦官方还提供了 defineModel() 用于简化上边的步骤
向子组件传递插槽我们以 input 组件作为例子,创建一个 WrapInput.vue 组件
未学习之前WrapInput.vue 常规的做法,遍历 $slots 来实现
scriptsetuplang="ts"
constmodel=defineModel()
/script
template
el-inputv-model="model"placeholder="Pleaseinput"
templatev-for="(_,slot)in$slots":key="solt"v-slot:[slot]="slotProps"
slot:name="slot"v-bind="slotProps"/slot
/template
/el-input
/template
stylelang='scss'scoped/style
在 app.vue 中引入并传递 prepend、append 插槽
scriptsetuplang="ts"
import{ref}from"vue";
importWrapInputfrom"./components/WrapInput.vue";
constinputText=ref('')
/script
template
WrapInputv-model="inputText"
template#prependHttp:///template
template#append.com/template
/WrapInput
div
{{inputText}}
/div
/template
stylescoped
/style
正确渲染了插槽
学习之后让我们来修改下 WrapInput.vue
scriptsetuplang="ts"
import{h}from"vue";
import{ElInput}from"element-plus";
constmodel=defineModel()
/script
template
component:is="h(ElInput,$attrs,$slots)"v-model="model"/component
/template
stylelang='scss'scoped/style
app.vue 的代码不做任何修改
插槽正常传递、数据更新正常,看到这种写法的时候有点震惊的
component 组件为什么可以传入h函数看下 h 函数的文档, h(ElInput, $attrs, $slots) 是创建了一个虚拟 dom 节点
而 component 组件的 is 属性则可以接收
被注册的组件名导入的组件对象一个返回上述值之一的函数当 component 组件的 is 属性接收到一个函数时,Vue 会调用这个函数并使用其返回值作为要渲染的组件。
在这种情况下,h(ElInput, $attrs, $slots)会立即执行并返回一个 VNode,这个 VNode 描述了如何渲染ElInput组件。
获取子组件的 ref未学习之前之前的自己的写法有点蠢的具体的做法是在子组件创建一个 getRef 的函数把 ref 暴露出去,父组件调用 getRef 方法后在执行子组件方法的调用,大概是下边这样
WrapInput1.vue
scriptsetuplang="ts"
import{h,ref}from"vue";
import{ElInput}from"element-plus";
constmodel=defineModel()
constinputRef=ref()
functiongetRef(){
returninputRef.value
}
defineExpose({
getRef
})
/script
template
componentref="inputRef":is="h(ElInput,$attrs,$slots)"v-model="model"/component
/template
stylelang='scss'scoped/style
学习之后WrapInput.vue
scriptsetuplang="ts"
import{h,ref}from"vue";
import{ElInput}from"element-plus";
constmodel=defineModel()
constinputRef=ref()
defineExpose(newProxy({},{
get(_target,prop){
returninputRef.value?.[prop]
},
has(_target,prop){
returnpropininputRef.value
}
}))
/script
template
component:is="h(ElInput,$attrs,$slots)"v-model="model"ref="inputRef"/component
/template
stylelang='scss'scoped/style
使用 Proxy 代理暴露出去的方法,是有点震惊的,还能这么写
App.vue
scriptsetuplang="ts"
import{ref}from"vue";
importWrapInputfrom"./components/WrapInput.vue";
constinputText=ref('')
constprependSlotText=ref('Http://')
constappendSlotText=ref('.com')
functionupdateSlotInfo(){
prependSlotText.value='https://'
appendSlotText.value=`${newDate().getTime()}`
}
constwrapInputRef=ref()
functionsetWrapInputFocus(){
wrapInputRef.value?.focus()
}
/script
template
WrapInputv-model="inputText"ref="wrapInputRef"
template#prepend{{prependSlotText}}/template
template#append{{appendSlotText}}/template
/WrapInput
divstyle="margin:20px"
{{inputText}}
/div
el-buttontype="primary"@click="updateSlotInfo"更新插槽内容/el-button
el-buttontype="primary"@click="setWrapInputFocus"setinputfocus/el-button
/template
stylescoped
/style
调用组件的 focus 方法让 WrapInput.vue 组件获取焦点
监听子组件的生命周期事件3.4 版本之前是 @vnode:XXX
总结本文实践了在 vue3 中在二次封装组件时如何实现 v-model、插槽传递、子组件 ref 获取
插槽传递通过向 component 组件的 is 属性传递 h 函数创建虚拟 dom 来实现
获取子组件的 ref 则是使用 new Proxy 的方式来实现
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线