Vue中的渲染函数(render函数)

节点、树以及虚拟 DOM

  • 当浏览器读到一些DOM结构时,会建立一个“DOM节点”树来保持追踪所有内容,如同你会画一张家谱树来追踪家庭成员的发展一样。

  • Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。

  • createElement 会返回一个虚拟节点 (virtual node)”,也常简写它为“VNode”。

  • “虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。

  • 虚拟DOM所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。

  • 每个DOM元素或组件都对应一个VNode对象。

渲染函数

  • 通过createElement函数来创建虚拟节点 (virtual node),用来渲染要渲染的节点。
  • 需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。
  • 可以解决有些场景中用template实现起来代码冗余,重复模板比较多时。
import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

new Vue({
    render: h => {
        console.log(h);
    //ƒ (a, b, c, d) { return createElement(vm, a, b, c, d, true); }
        return h(App);
    }
}).$mount("#app");
  ƒ (a, b, c, d) { return createElement(vm, a, b, c, d, true); }
  • render函数:createElement是render函数的参数,它本身也是个函数。

使用render函数的写一个to do list(Vue 的模板实际上被编译成了渲染函数)

import Vue from "vue";

const AddHeros = {
    props: {
        heros: {
            type: Array,
            default: () => []
        },
        add: {
            type: Function
        }
    },
    data() {
        return {
            name: "",
            job: ""
        };
    },
    render(createElement) {
        return createElement(
            "div",
            {
                style: {
                    display: "flex",
                    "align-items": "center",
                    justifyContent: "space-between",
                    marginBottom: "5px"
                }
            },
            [
                createElement("span", {}, [
                    createElement("span", "英雄名:"),
                    createElement("input", {
                        attrs: {
                            placeholder: "请输入英雄名"
                        },
                        style: {
                            width: "150px"
                        },
                        on: {
                            input: e => {
                                this.name = e.target.value;
                            }
                        }
                    })
                ]),
                createElement("span", {}, [
                    createElement("span", "职业:"),
                    createElement("input", {
                        attrs: {
                            placeholder: "请输入英雄职业"
                        },
                        style: {
                            width: "150px"
                        },
                        on: {
                            input: e => {
                                this.job = e.target.value;
                            }
                        }
                    })
                ]),
                createElement(
                    "button",
                    {
                        on: {
                            click: () => {
                                let id = ++this.$props.heros[
                                    this.$props.heros.length - 1
                                ].id;
                                this.$props.add({
                                    id: id,
                                    name: this.name,
                                    job: this.job
                                });
                                debugger;
                                this.name = "";
                                this.job = "";
                            }
                        }
                    },
                    "添加"
                )
            ]
        );
    }
};

// 函数式组件
const HerosList = {
    functional: true,
    render: function(createElement, context) {
        const HerosItem = context.data.props.heros.map(item => {
            return createElement(
                "li",
                {
                    style: {
                        display: "flex",
                        "align-items": "center",
                        justifyContent: "space-between",
                        padding: "0 10px",
                        height: "40px",
                        border: "1px solid #ccc"
                    }
                },
                [
                    createElement(
                        "div",
                        {
                            style: {
                                width: "70px"
                            }
                        },
                        item.name
                    ),
                    createElement("div", {}, item.job),
                    createElement(
                        "div",
                        {
                            style: {
                                width: "90px",
                                display: "flex",
                                "align-items": "center",
                                justifyContent: "space-between",
                                cursor: "pointer"
                            }
                        },
                        [
                            createElement(
                                "button",
                                {
                                    on: {
                                        click: () => {
                                            context.data.on.edit();
                                        }
                                    }
                                },
                                "修改"
                            ),
                            createElement(
                                "button",
                                {
                                    on: {
                                        click: () => {
                                            context.data.nativeOn.del(item.id);
                                        }
                                    }
                                },
                                "删除"
                            )
                        ]
                    )
                ]
            );
        });

        return createElement(
            "ul",
            {
                style: {
                    "list-style": "none",
                    width: "100%",
                    padding: 0,
                    margin: 0
                }
            },
            HerosItem
        );
    }
};

const HerosListWrep = {
    name: "HerosListWrep",
    data() {
        return {
            heros: []
        };
    },
    created() {
        // 初始英雄列表
        this.heros = this.HEROS;
    },
    computed: {
        HEROS() {
            const heros = [
                { id: "1", name: "鲁班七号", job: "射手" },
                { id: "2", name: "铠", job: "战士" },
                { id: "3", name: "小乔", job: "法师" },
                { id: "4", name: "刘禅", job: "辅助" },
                { id: "5", name: "孙悟空", job: "刺客" }
            ];
            return heros;
        }
    },
    methods: {
        // 添加英雄
        add(herosItem) {
            this.heros.push(herosItem);
        }
    },
    render(createElement) {
        return createElement(
            "div",
            {
                style: {
                    margin: "0 auto",
                    width: "500px",
                    paddingTop: "100px"
                }
            },
            [
                createElement(AddHeros, {
                    props: {
                        heros: this.heros,
                        add: this.add
                    },

                    nativeOn: {
                        click: () => {
                            console.log(
                                "仅用于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。"
                            );
                        }
                    }
                }),
                createElement(HerosList, {
                    props: {
                        heros: this.heros
                    },
                    on: {
                        edit: () => {
                            console.log("编辑");
                        }
                    },
                    nativeOn: {
                        del: id => {
                            let arr = this.heros.filter(item => item.id != id);
                            this.heros = arr;
                        }
                    }
                })
            ]
        );
    }
};

new Vue({
    render(h) {
        return h(
            "div",
            {
                attrs: {
                    id: "app"
                }
            },
            [h(HerosListWrep)]
        );
    }
}).$mount("#app");

渲染函数参考: https://cn.vuejs.org/v2/guide/render-function.html

函数式组件参考: https://cn.vuejs.org/v2/guide/render-function.html#函数式组件

posted @ 2019-08-31 22:18  氵灬  阅读(1081)  评论(0编辑  收藏  举报