说在前面
slot这个功能好像平时需求中很少能用到,感觉没有使用它的场景,即使有时候发现有个场景可以用slot,但是实际能用slot的地方基本上可以把那一段代码抽取一个单独组建,通过 父子组件嵌套即可替代slot功能,或者即使使用了也是简单一个插槽传过去占位置使用,并没有数据传递,发挥真正的作用
下面的需求感觉是非常适合用slot解决模板复用的,同时利用作用于插槽解决数据传递,用抽取组建的形式就不太好,
需求:
现有一个基于template语法编写的单文件vue组件,其中有一个树表格table,有一天我们有一个新需求,需要点击一个按钮切换成普通的table组件,
普通的table组件的要求是,原来的树表格table的每一列在新的table组件中都包含,而且会新增加几列新数据,同时某些表头要支持筛选, 服务端会提供一个新接口
那么,我们如何做到呢?
需求分析,
新table并不是完全新组件,和原来树状table有很多相同点,我们要要可考虑复用的点,
相同点
1 原来树状table的列,如 名称,编码等
不同点
1 新增的列如何实现 2 如果原来的列需要调整顺序,或者展示规则变了需要如何调整
实现
1,方法1 就是在当前组件中继续写一个新的table,(从当前table复制出来一个魔改,当然相应的以来的data数据都要拷贝一份新数据), 这样是写的时候最省事的, 但是维护的时候会非常痛苦,这种写法会使当前组件多个无关数据都糅杂在一起,同时新老table里的tableColumns几乎都是重复复制的,
2 优化的方案就是 新写一个新table组件,这样新老table组件的data可以隔离开了,但是tableColumns里的模板复用如何解决
1 最容易想到的方式--抽取组件 (这也是通义灵码建议的方式)
抽取前有一个新问题,要抽取的模板中依赖的方法(如showEditButton,showMappingButton),是保留在父组件中,然后通过props传递到新组件,还是直接抽取到新组件,作为组件的自己的方法?
通义灵码建议抽取到新组件
然后父组件这么使用
当然我们新的table组件 NewTable也可以这样嵌入组件,这样复用的需求实现了,
但是实际有一个问题,就是抽取到DynamicContent组件的showEditButton等方法,
在父组件中依赖了父组件的data里的数据, 我们如果继续把父组件的data里的数据也移动到DynamicContent,这样改动太大,
同时该方法 还被父组件的其他地方引用,所以该方法无法被子组件私有,除非用mixin继续抽取该方法(但是mixin不建议使用)
豆包的建议用jsx
然而实际按照这个方法一直报错,感觉在template写法中无法引入jxs,如果父组件用的是jsx而不是template写法,则可完美解决
最终解决
所以我们采用了抽取组件 DynamicContent,但是依赖的方法保留在父组件中,通过props传递过去
DynamicContent中只有模板的实现,没有业务逻辑,所以,以后有业务逻辑修改依然在父组件中修改,避免一份逻辑散落多处
同时 DynamicContent 下级的子组件,通过
v-bind="$attrs" v-on="$listeners"
透传过去,避免DynamicContent中写太多不是自己需要的props
最后是我们的NewTable组件,在这个组件里可以声明自己的 data, column,数据,
同时,通过slot将自己遍历的数据 传递到父组件中传过来DynamicContent组件,可以看到这样 DynamicContent所
声明的方法如showEditButton,我们也实现了复用,
那如果NewTable中新增的几列数据,或者原来的列(如名称),需要仅仅在NewTable中特殊处理,可以按照图中,优先用if判断,这样即实现了相同点的复用也实现了不同点的定制,