render函数

render函数

通常我们都会把我们的页面结构逻辑都写在 template 中,然后再通过vue将我们的代码转换成虚拟DOM,相比于真实DOM,虚拟DOM是通过js代码处理的,所以消耗的性能相对较小,当然大部分情况下使用 template 创建我们的HTML是可以的,但是在有些场景下,我们真的需要通Javascript的完全编程的能力来完成时,就可以用到 render函数,比之 template 更接近编译器

render函数的作用就是返回一个虚拟dom,将该虚拟dom渲染成真实的dom。

render函数的参数

render函数即渲染函数,它是个函数,render返回的参数是Vnode(即虚拟节点,也就是我们要渲染的节点)

createElement是render函数返回的参数,它本身也是一个函数,并且有3个参数:

第一个参数(必填):可以为String|Object|Function

  • String:表示的是HTML 标签名;
  • Object :一个含有数据的组件选项对象;
  • Function :返回了一个含有标签名或者组件选项对象的async函数。

第二个参数(选填):可为Class|Style|attrs|domProps|on

  • class:控制类名;
  • style :样式;
  • attrs :用来写正常的 html 属性 id src 等;
  • domProps :用来写原生的dom 属性;
  • on:用来写原生方法;

第三个参数(选填):代表子级虚拟节点,由 createElement() 构建而成,正常来讲接收的是一个字符串或者一个数组,一般数组用的是比较多的

参数二详细参数

            {
                // 与 `v-bind:class` 的 API 相同,
                // 接受一个字符串、对象或字符串和对象组成的数组
                'class': {
                    foo: true,
                    bar: false
                },
                // 与 `v-bind:style` 的 API 相同,
                // 接受一个字符串、对象,或对象组成的数组
                style: {
                    color: 'red',
                    fontSize: '14px'
                },
                // 普通的 HTML attribute
                attrs: {
                    id: 'foo'
                },
                // 组件 prop
                props: {
                    myProp: 'bar'
                },
                // DOM property
                domProps: {
                    innerHTML: 'baz'
                },
                // 事件监听器在 `on` 内,
                // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
                // 需要在处理函数中手动检查 keyCode。
                on: {
                    click: this.clickHandler
                },
                // 仅用于组件,用于监听原生事件,而不是组件内部使用
                // `vm.$emit` 触发的事件。
                nativeOn: {
                    click: this.nativeClickHandler
                },
                // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
                // 赋值,因为 Vue 已经自动为你进行了同步。
                directives: [
                    {
                        name: 'my-custom-directive',
                        value: '2',
                        expression: '1 + 1',
                        arg: 'foo',
                        modifiers: {
                            bar: true
                        }
                    }
                ],
                // 作用域插槽的格式为
                // { name: props => VNode | Array<VNode> }
                scopedSlots: {
                    default: props => createElement('span', props.text)
                },
                // 如果组件是其它组件的子组件,需为插槽指定名称
                slot: 'name-of-slot',
                // 其它特殊顶层 property
                key: 'myKey',
                ref: 'myRef',
                // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
                // 那么 `$refs.myRef` 会变成一个数组。
                refInFor: true
            }

示例

父组件

<template>
        <div class="container">
                <AnchoredHeading :level="2">222</AnchoredHeading>
        </div>
</template>
    <script>
    import AnchoredHeading from "./test_add";
    export default {
        name: "RenderDemo",
        components: {
            AnchoredHeading
        },
        data () {
            return {};
        },
        methods: {},
    };
    </script>
<style scoped>

</style>

子组件

<script>
export default {
    name: "AnchoredHeading",
    render: function (createElement, context) {
        return createElement(
            "h" + this.level, // 标签名称
            this.$slots.default // 子节点数组
        );
    },
    props: {
        level: {
            type: Number,
            required: true
        }
    }
};
</script>

最终效果

注意:template和render不能一起使用,否则无效

v-if和v-for

只要是在原生的JavaScript中可以轻松完成的操作,Vue渲染函数就不会提供专有的代替方法,比如在模板中使用的v-if和v-for。

        <ul v-if="level.length">
            <li v-for="item in level">{{ item.name }}</li>
        </ul>

这些都可以在渲染函数中用 JavaScript 的 if/else 和 map 来重写:

子组件:

<script>
export default {
    props: ["level", "title"],
    render (h) {
        console.log("this.$slots.default :>> ", this.$slots.default);
        if (this.level.length) {
            return h("ul", this.level.map((item) => {
                return h("li", item.name)
            }));
        } else {
            return h("p", "这是p元素")
        }

    },

};
</script>

父组件:

<template>
    <div>
        <heading :level="level">
            {{ title }}
        </heading>
    </div>
</template>
  
<script>
import Heading from "./test_add.vue";
export default {
    components: { Heading },
    data () {
        return {
            level: [
                { name: '这是li' },
                { name: '这是li' },
                { name: '这是li' },
                { name: '这是li' },
                { name: '这是li' },
                { name: '这是li' },
                { name: '这是li' },
                { name: '这是li' },
            ],
        };
    },
};
</script>

最终效果:

事件 & 按键修饰符

对于 .passive、.capture 和 .once 这些事件修饰符,Vue 提供了相应的前缀可以用于 on:

修饰符

前缀

.passive

&

.capture

!

.once

~

.capture.once 
.once.capture

~!

on: {
        '!click': this.doThisInCapturingMode,
        '~keyup': this.doThisOnce,
        '~!mouseover': this.doThisOnceInCapturingMode
     }

这里是一个使用所有修饰符的例子:

                on: {
                    keyup: function (event) {
                        // 如果触发事件的元素不是事件绑定的元素
                        // 则返回
                        if (event.target !== event.currentTarget) return
                        // 如果按下去的不是 enter 键或者
                        // 没有同时按下 shift 键
                        // 则返回
                        if (!event.shiftKey || event.keyCode !== 13) return
                        // 阻止 事件冒泡
                        event.stopPropagation()
                        // 阻止该元素默认的 keyup 事件
                        event.preventDefault()
                        // ...
                    }
                }

插槽

你可以通过 this.$slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组:

                render: function (createElement) {
                    // `<div><slot></slot></div>`
                    return createElement('div', this.$slots.default)
                }

也可以通过 this.$scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数:

                props: ['message'],
                render: function (createElement) {
                    // `<div><slot :text="message"></slot></div>`
                    return createElement('div', [
                        this.$scopedSlots.default({
                            text: this.message
                        })
                    ])
                }

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>