在vue template模板中使用render函数的方法

1,244 阅读1分钟

在某些场景下,一个组件用template语法写比较简单,或者历史代码就是使用template写的,现在我们要扩展它的功能,要求它的某个props可以传入一个render函数,要求template可以将这个props正常渲染出来,怎么办?

代码示例:

示例是一个表单项组件,正常的值可以直接渲染,但是一些字典类的(如性别)需要加工渲染,改造后的代码如下:

子组件代码:

<template>
    <div class="form-item">
        <div class="label">{{item.label}}:</div>
        <div class="value" v-if="defaultRender">{{item.value}}</div>
        <value-node class="value" v-else :vnodes="vnodes"></value-node>
    </div>
</template>

<script>
export default {
    name: "formItem",
    components: {
        "value-node": {
            functional: true,
            render(h, ctx) {
                return ctx.props.vnodes(h)
            }
        }
    },
    props: {
        item: {
            type: Object,
            default: () => ({})
        }
    },
    computed: {
        defaultRender() {
            return !this.item.renderFn
        }
    },
    methods: {
        vnodes(h) {
            return this.item.renderFn && this.item.renderFn(h, this.item)
        }
    }
}
</script>

<style lang="css">
.form-item {
    display: flex;
}

</style>

父组件调用代码:

<template>
    <div id="app">
        <form-item v-for="(item) in formOptions" :key="item.key" :item="item"></form-item>
    </div>
</template>

<script>
import formItem from "./components/formItem.vue";
export default {
    name: "App",
    components: { formItem },
    data() {
        return {
            formOptions: [
                {
                    key: "user-name",
                    label: "用户名",
                    value: "张三",
                },
                {
                    key: "user-sex",
                    label: "性别",
                    value: "1",
                    renderFn(h, item) {
                      // eslint-disable-next-line no-console
                      console.log(item)
                        return <span>{item.value == "1" ? "男" : "女"}</span>;
                    },
                },
            ],
        };
    },
};
</script>


渲染结果:

注意传进去的item的渲染函数名称不要叫做render,否则会被当成vue组件。