template不行?使用render函数开发动态组件

背景

今天在开发某个需求的时候遇到了一个问题,某个组件的一些html标签需要根据props定义的tag字段自定义传入,生成对应的divpspan等标签显示在页面中,并且tag不固定(排除了枚举所有标签并使用v-if控制实现的可能)。但是vue2.x的模板语法只支持在template中添加某些确定的标签,无法实现,于是想到了使用render函数来实现。

用法:

Vue推荐在大多数的情况下使用模板创建html,然而在一些模板语法不能满足的特殊场景下,我们可以通过render函数使用JavaScript来构建dom。例如:


render(createElement){
	return createElement('div','这是需要显示的文字')
}

使用vue进行开发的人员都知道,Vue通过创建一个虚拟dom来追踪自己想要改变的真实dom。所以createElement返回的并不是一个真实的dom,官网给了一个更准确名字createNodeDescription:因为它包含的信息会告诉vue页面上需要渲染什么样的节点,包括及其子节点的描述信息。这样的节点被称为虚拟节点virtual node),也就是常说的VNode

createElement的三个参数:

【1】String | Object | Function :必填,可以是一个html标签,或者包含标签数据的

【2】Object : class | style | attrs | domProps | on 等

【3】String | Array

注意:

template模板语法不能跟render函数连用,render优先并且会覆盖模板内容。

最后使用render函数完成的核心代码如下:


<script>
    export default {
        name:'ai-row',
        methods:{
          handleClick(e){
              this.$emit('click',e);
          }  
        },
        render(createElement){
            return createElement(
            	this.tag,
                {
                    props:{
                        tag:{
                            type:String,
                            default:'div'
                        },
                        classes:{
                            type:Array,
                            default:()=>['ai-row']
                        }
                    },
                    class:this.classes,
                    style:{
                        fontSize:'14px'
                    },
                    attrs:{
                        id:'ai-row-main',
                        placeholder:'在此输入...'
                    },
                    domProps:{
                        ref:'rowRef'
                    },
                    on:{
                        click:(e)=>{
                            this.handleClick(e);
                        }
                    }
                },
                this.$slots.default
            )
        }
    }
</script>
posted @ 2025-05-18 12:22  Justus-  阅读(43)  评论(0)    收藏  举报