注册
web

分享VUE3编写组件高级技巧,优雅!

在这里,主要分享一些平时写VUE组件,会用到一些技巧,会让代码得到很大的简化,可以节省很多脑力体力。


1、v-bind=“$attrs”


这是首推的一个技巧写法,特别在拓展开源组件时,无缝使用开源组件各种props值时,简直不要太爽。


比如element-ui组件中的select组件,就有一个让人痛恨的点,就是options数据无法配置,必须得手动引入option组件才行,如下:


 <el-select v-model="value" placeholder="Select" size="large">  
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>

身为一个优秀前端前端佬,这哪里能忍!


技巧随之用来,我们就可以使用上面这个,创建一个自定义select组件,既能享用原组件的各种配置属性和事件
(P.S. 如果需要组件上使用自定义事件,比如change事件,属性上定义为’onChange': ()=>{}。),也可以自定义一些功能,创建一个customSelect.vue:


<el-select v-model="selectedValue" v-bind="attts">
<el-option v-for="(item) in customOptions" v-bind="item"/>
</el-select>

这样在动态引用这个组件,就能使用自定义的customOptions这个属性。


上面例子主要说明,v-bind="$attr"的好处。但还是得多说一句,上面例子中的一些缺点。



  1. 无法直接使用el-select对外暴露的方法;
  2. 无法直接使用el-select的slot分发;

然后需要注意一个点,得在customSelect.vue组件中,设置inheritAttrs为false,防止数据在组件上一层层透传下去。


2、improt { h } from vue


h为vue中的渲染函数,主要用来创建虚拟 DOM 节点 (vnode)。对应参数,可以戳这里,看官方详细正宗介绍。


对应这个连接中,有很多渲染函数的介绍。这系列有一个很大的特点,那就是用的魔怔了,就会一不小心把VUE变成“React”,损失掉VUE框架中的一些优点。


自由度非常高。仅仅针对这个H函数举例,还是援用上面的例子,实现如下(代码片段):


<scirpt>
import {defineComponent, h} from 'vue'
import {ElSelect, ElOption} from 'element-plus'

export default definComponent({
name:'DynamicSelect',
props:{
options:{
type:Array,
required:true,
default:() => []
}
},
setup(props) {
return () = >
h(ElSelect, () =>
props.options.map(options =>
h(ElOption, {
key:option.value,
label:option.label,
value:option.value,
})
)
)
}
})
<script>

足够清爽,简单。


3、render


render,用于编程式地创建组件虚拟 DOM 树的函数。解释链接,可以戳这里


废话不多说,直接以上面的例子,用render方式撸一遍。


<!-- <template>
<div>1</div>
<template> -->

<scirpt>
import {defineComponent, h} from 'vue'
import {ElSelect, ElOption} from 'element-plus'

export default definComponent({
name:'DynamicSelect',
props:{
options:{
type:Array,
required:true,
default:() => []
}
},
render(_ctx) {
return () = >
h(ElSelect, () =>
_ctx.options.map(options =>
h(ElOption, {
key:option.value,
label:option.label,
value:option.value,
})
)
)
}
})
<script>

不能说实现的方式跟上面相似,简直说是一模一样。主要在于render做了template要做的事,但相比较template少一层解析,理论上会比template更高效。


需要注意一点,这里放出官网的描述:



如果一个组件中同时存在 render 和 template,则 render 将具有更高的优先级



正常理解的话,是render渲染出的vnode会高于template解析出的vnode,同时存在,render会覆盖掉template。


但在经过VUE的v3.3.4版本中操作,template会覆盖掉render。所以这个优先级,猜测可能是render会优先解析,具体得翻源码,待理解后继续更新。


4、getCurrentInstance


这个是获取当前组件实例的方法,属于核弹级别的方法,也属于VUE3官网文档中翻不到的东西。


但鲁迅说的好,路走的多了,那就成路了。如果社区用的人多了,那么它就有可能提上去!


image.png


言归正传,那么拿了这个组件的实例,能干什么呢?


那可干的事情,就可多可多了。


比如改个,调个组件方法,这都算小儿科,完全不用担心这里readOnly,那里ReadonlyReactiveHandler


猛一点,直接硬插,换个上下文。



再猛的,先假设:组件实例 === 组件,组件 === VUE,VUE === YYX写的,然后你写了一点代码+VUE,是不是由此可得,你的代码 》 VUE ,进而证明 你 》 YYX。嗯?


93B1A00879A9B67271080936B8A2D89CE1D69417_size242_w423_h220.gif


5、extends


先来一段官方的介绍:



从实现角度来看,extends 几乎和 mixins 相同。通过 extends 指定的组件将会当作第一个 mixin 来处理。


然而,extends 和 mixins 表达的是不同的目标。mixins 选项基本用于组合功能,而 extends 则一般更关注继承关系。



缺点上,第1节有提一个,但还有一个不算是缺点的缺点,相同属性和方法会直接覆盖被继承的组件(钩子函数不会被覆盖),主要在于是否熟悉被继承的组件中的逻辑。用的好就很好,用的不行,就真的很不行。


如果还是用上面的例子作为例子,实现方法如下:


<scirpt>
import {defineComponent, createVNode, render, getCurrentInstance } from 'vue'
import {ElSelect, ElOption} from 'element-plus'

export default definComponent({
name:'DynamicSelect',
extends:ElSelect,
props:{
options:{
type:Array,
required:true,
default:() => []
}
},
setup(props) {
return ElSelect.setup(props, context)
},
mounted(){
const curInstance = getCurrentInstance()
const container = doucment.createElement('div')

this.$props.options.forEach(options => {
const vNode = createVNode(ElOption,{
key:option.value,
label:option.label,
value:option.value,
})
})

const currrentProvides = curInstance?.provides
if(currrentProvides){
// 将ELSelect的Provides,传入到ElOption中
reflect.set(curInstance?.appContext,'provides',{...currrentProvides})
}
vNode.appContext = curInstance?.appContext
render(vNode,container)
this.$el.appendChild(container)
}
})
<script>

但这种,确实是为了实现那个例子而写的代码。有些可以作为参考。


暂时分享这些,欢迎前端佬们拍砖。


作者:大怪v
来源:juejin.cn/post/7450836153258049572

0 个评论

要回复文章请先登录注册