是什么?

render 函数模板(template) 都是用来创建 html 模板的,Vue 推荐在绝大多数情况下使用模板(template)来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。

绝大多数情况下使用模板(template)来创建你的 HTML是这个样子的。

<!--HelloWorld.vue-->
<template>
  <div id="app">
    Hello World!!!
  </div>
</template>

render渲染函数是这个样子的。(修改HelloWorld.vue为render函数创建模板的形式)

<!--HelloWorld.vue-->
<script>
export default {
  //不用vue模板,使用render函数进行dom渲染,h->createElement
  //vue模板template最终也是要编译成render函数
  render(createElement){
    return createElement(
        //第一个参数:写一个 HTML 标签名、组件选项对象
        //或者resolve 了上述任何一种的一个 async 函数。必填项。
        'h1',
        //第二个参数:一个与模板中 attribute 对应的数据对象。
        //可选(具体参数见:https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1)。
        {},
        //第三个参数:子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
        //也可以使用字符串来生成“文本虚拟节点”。可选。
        "Hello World!!!"
    )
  }
  
};
</script>

效果都是一样的。vue模板template最终也是要编译成render函数

在这里插入图片描述

如何使用?

1. createElement的第一个参数

1.1 HTML 标签名(可以动态创建标签)

<!--HelloWorld.vue-->
<script>
export default {
  //传参
  props: {
    tag: {
      type: String,
      required: true,
    },
  },
  //不用vue模板,使用render函数进行dom渲染,h->createElement
  //vue模板template最终也是要编译成render函数
  render(createElement) {
    return createElement(this.tag, {}, "Hello World!!!");
  },
};
</script>
<!--父组件-->
<HelloWorld tag="h2"/>

这样就通过父子组件的传参实现了动态的创建标签。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T8l33lwG-1640198332892)(C:\Users\25218\AppData\Roaming\Typora\typora-user-images\image-20211223013219794.png)]

1.2 组件

我定义了一个MyButton的按钮组件(样式模仿了Element-ui),也是通过render函数渲染出来的组件。

<!--MyButton.vue-->
<script>
export default {
  //传参
  props: {
    type: {
      type: String,
      default: "normal",
    },
    text: {
      type: String,
      default: "",
    },
  },
  //渲染函数
  render(createElement) {
    return createElement("button", {
      //v-bind:class
      class: {
        btn: true,
        "btn-success": this.type === "success",
        "btn-error": this.type === "error",
        "btn-warning": this.type === "warning",
        normal: !this.type,
      },
      //dom属性
      domProps: {
        innerText: this.text || "默认按钮",
      },
    });
  },
};
</script>

<style scoped>
.btn {
  border: rgb(216, 224, 235) 1px solid;
  width: 100px;
  height: 40px;
  border-radius: 10px;
  cursor: pointer;
  font-weight: 500;
}

.normal {
  background: #fff;
  border: 1px solid #dcdfe6;
  color: rgb(96, 98, 102);
}
.btn:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background-color: #ecf5ff;
}

.btn-success {
  color: #fff;
  background-color: #67c23a;
  border-color: #67c23a;
}

.btn-success:hover {
  background: #85ce61;
  border-color: #85ce61;
  color: #fff;
}

.btn-error {
  color: #fff;
  background-color: #f56c6c;
  border-color: #f56c6c;
}

.btn-error:hover {
  background: #f78989;
  border-color: #f78989;
  color: #fff;
}

.btn-warning {
  color: #fff;
  background-color: #e6a23c;
  border-color: #e6a23c;
}

.btn-warning:hover {
  background: #ebb563;
  border-color: #ebb563;
  color: #fff;
}
</style>
<!--HelloWorld.vue-->
<script>
import MyButton from "./MyButton.vue";
export default {
  //第一个参数为组件
  render(createElement) {
    return createElement(MyButton, {
      //MyButton组件需要type和text的参数
      props: {
        //按钮类型
        type: "error",
        //按钮文字
        text: "",
      },
    });
  },
};
</script>

这样就出来了一个error类型的按钮。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4fsycNRz-1640198332893)(C:\Users\25218\AppData\Roaming\Typora\typora-user-images\image-20211223023126098.png)]

2. createElement的第二个参数

2.1 attrs

<!--HelloWorld.vue-->
<script>
export default {
  //不用vue模板,使用render函数进行dom渲染,h->createElement
  //vue模板template最终也是要编译成render函数
  render(createElement) {
    return createElement(
      "div",
      {
        attrs: {
          class: "test",
        },
      },
      "Hello World!!!"
    );
  },
};
</script>

<!--使用渲染函数定义了class之后,直接在style标签中定义样式就可以使用了-->
<style scoped>
.test {
  color: red;
  font-size: 20px;
}
</style>

这样就定义了attrs中的class属性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ptCMZJ29-1640198332894)(C:\Users\25218\AppData\Roaming\Typora\typora-user-images\image-20211223015524941.png)]

2.2 on(事件监听器在 on 内)

<!--HelloWorld.vue-->
<script>
export default {
  //不用vue模板,使用render函数进行dom渲染,h->createElement
  //vue模板template最终也是要编译成render函数
  render(createElement) {
    return createElement(
      "div",
      {
        class: "test",
        on: {
          click: function () {
            console.log("执行点击事件");
          },
        },
      },
      "Hello World!!!"
    );
  },
};
</script>

<!--使用渲染函数定义了class之后,直接在style标签中定义样式就可以使用了-->
<style scoped>
.test {
  color: red;
  font-size: 20px;
}
</style>

点击字体时触发点击事件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-znAuHTem-1640198332896)(C:\Users\25218\AppData\Roaming\Typora\typora-user-images\image-20211223015843386.png)]

3. createElement的第三个参数

3.1 文本虚拟节点

同第一节的内容,写了一个 “Hello World!!!” 的内容

3.2 子级虚拟节点 (VNodes)

<!--HelloWorld.vue-->
<script>
export default {
  data: function () {
    return {
      tag: "ul",
      numArr: [1, 2, 3, 4],
    };
  },
  //不用vue模板,使用render函数进行dom渲染,h->createElement
  //vue模板template最终也是要编译成render函数
  render(createElement) {
    return createElement(
      this.tag,
      {},
      this.numArr.map((item) => {
        return createElement("li", {}, `${item}`);
      })
    );
  },
};
</script>

效果就是一个”ul“节点下包含着4个”li“节点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJrJu7Dc-1640198332897)(C:\Users\25218\AppData\Roaming\Typora\typora-user-images\image-20211223014735949.png)]

以上就是render渲染函数最基本的内容。

我是前端Dai,一个会将自己平时项目中常见的问题以及笔试面试的知识在CSDN与大家分享的coder,希望大家一起进步,加油。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐