1.Render函数:render是用来替换temlate的,需要更灵活的模板的写法的时候,用render。

官网API地址:https://cn.vuejs.org/v2/guide/render-function.html

通常写的h为createElement的缩写,createElement 会返回虚拟节点 (virtual node)”,也常简写它为“VNode,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。

  • 第一个参数为{String | Object | Function}是一个 HTML 标签名、组件选项对象,为必选项。
  • 第二个参数为 {Object},是一个与模板中属性对应的数据对象。可选。
  • 第三个参数为{String | Array},是子级虚拟节点 (VNodes),由 `createElement()` 构建而成,也可以使用字符串来生成“文本虚拟节点”。可选。

1.1一个最简单的render函数例子:

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import router from "./router";
  4. import store from "./store";
  5. import Bus from "./lib/bus";
  6. import $ from "jquery";
  7.  
  8. Vue.config.productionTip = false;
  9. Vue.prototype.$bus = Bus;
  10.  
  11. new Vue({
  12. router,
  13. store,
  14. //render: h => h(App)
  15. render(h) {
  16. return h('div', {
  17. attrs: {
  18. id:"box"
  19. },
  20. style: {
  21. color:"blue"
  22. }
  23. },"Caoqi");
  24. },
  25. }).$mount("#app");

1.2当第一个参数为组件时的写法如下,引入的组件为之前博客中讲过的Count-To组件(https://www.cnblogs.com/qicao/p/10805715.html)

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import router from "./router";
  4. import store from "./store";
  5. import Bus from "./lib/bus";
  6. import $ from "jquery";
  7. import CountTo from "_c/count-to";
  8.  
  9. Vue.config.productionTip = false;
  10. Vue.prototype.$bus = Bus;
  11.  
  12. new Vue({
  13. router,
  14. store,
  15. render: function(h) {
  16. return h(CountTo, {
  17. /**
  18. * class作为一个保留字必须用引号包裹
  19. * 接受一个字符串、对象或字符串和对象组成的数组
  20. */
  21. // 'class':'count-up wrapper',
  22. //class: ["count-to", true ? "classA" : "classB"],
  23. class: { "count-to": 1 === 1 },
  24. // 组件 prop
  25. props: { endVal: 200 },
  26. // DOM 属性
  27. domProps: {
  28. //innerHTML: "baz"
  29. },
  30. /**
  31. * 事件监听器在 `on` 属性内,
  32. * 但不再支持如 `v-on:keyup.enter` 这样的修饰器。需要在处理函数中手动检查 keyCode。
  33. */
  34. on: {
  35. "on-animation-end": function(val) {
  36. console.log("animation end");
  37. }
  38. },
  39. /**
  40. * 仅用于组件,用于监听原生事件,而不是组件内部使用`vm.$emit` 触发的事件。
  41. */
  42. nativeOn: {
  43. click: () => console.log("I am clicked!")
  44. },
  45. /*自定义指令*/
  46. directives: [],
  47. // 如果组件是其它组件的子组件,需为插槽指定名称
  48. slot: "name-of-slot"
  49. });
  50. }
  51. }).$mount("#app");

显示效果:

1.3 创建子级虚拟节点:

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import router from "./router";
  4. import store from "./store";
  5. import Bus from "./lib/bus";
  6. import $ from "jquery";
  7. import CountTo from "_c/count-to";
  8.  
  9. Vue.config.productionTip = false;
  10. Vue.prototype.$bus = Bus;
  11.  
  12. new Vue({
  13. router,
  14. store,
  15. /**
  16. * @param {String | Array} h
  17. * 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,也可以使用字符串来生成“文本虚拟节点”。可选。
  18. */
  19. //render:h=>h('div','123')
  20. render:function(h) {
  21. return h('div', [
  22. h('span','span1'),
  23. h('span','span2'),
  24. ])
  25. }
  26. }).$mount("#app");

1.4使用 JavaScript 代替模板功能

模板代码:

  1. <template>
  2. <div>
  3. <ul @click="handlerClick">
  4. <li
  5. @click.stop="handlerClick"
  6. v-for="(item,index) in list"
  7. :key="`list_item_${index}`"
  8. >{{item.name}}</li>
  9. </ul>
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. data() {
  15. return {
  16. list: [
  17. {
  18. name: "张三"
  19. },
  20. {
  21. name: "李四"
  22. }
  23. ]
  24. };
  25. },
  26. methods: {
  27. handlerClick: function(event) {
  28. console.log(event);
  29. }
  30. }
  31. };
  32. </script>

main.js:

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import router from "./router";
  4. import store from "./store";
  5. import Bus from "./lib/bus";
  6. import $ from "jquery";
  7. import CountTo from "_c/count-to";
  8.  
  9. Vue.config.productionTip = false;
  10. Vue.prototype.$bus = Bus;
  11.  
  12. new Vue({
  13. router,
  14. store,
  15. render: h => h(App)
  16. }).$mount("#app");

若使用render函数中的js代替模板:只要在原生的 JavaScript 中可以轻松完成的操作,Vue 的渲染函数就不会提供专有的替代方法。比如,在模板中使用的 v-if 和 v-for需要用JavaScript 的 if/else 和 map 来重写:

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import router from "./router";
  4. import store from "./store";
  5. import Bus from "./lib/bus";
  6. import $ from "jquery";
  7. import CountTo from "_c/count-to";
  8.  
  9. Vue.config.productionTip = false;
  10. Vue.prototype.$bus = Bus;
  11.  
  12. const handleClick = event => {
  13. console.log(event);
  14. event.stopPropagation();
  15. };
  16.  
  17. let list = [{ name: "张三" }, { name: "李四" }];
  18. /**
  19. * Array map用法:
  20. * 功能:将原数组映射成新数组
  21. * https://www.zhangxinxu.com/wordpress/2013/04/es5%E6%96%B0%E5%A2%9E%E6%95%B0%E7%BB%84%E6%96%B9%E6%B3%95/#map
  22. */
  23. const getLiEleArr = h => {
  24. return list.map((item,index) =>
  25. h(
  26. "li",
  27. {
  28. on: {
  29. click: handleClick
  30. },
  31. key:`list_item_${index}`
  32. },
  33. item.name
  34. )
  35. );
  36. };
  37. /**等效于 */
  38. /*function getLiEleArr(h) {
  39. return list.map(function(item, index) {
  40. return h(
  41. "li",
  42. {
  43. on: {
  44. click: handleClick
  45. },
  46. key: `list_item_${index}`
  47. },
  48. item.name
  49. );
  50. });
  51. }*/
  52.  
  53. new Vue({
  54. router,
  55. store,
  56. render: function(h) {
  57. return h(
  58. "ul",
  59. {
  60. on: {
  61. click: handleClick
  62. }
  63. },
  64. getLiEleArr(h)
  65. );
  66. }
  67. }).$mount("#app");

2.函数式组件:函数组件可以用render方式,可以用模板方式。函数组件主要用来做组件的外壳,也就是写模板之前,可以先对传进来的上下文做一些处理。这个“壳”的作用有点类似模板语法里的<template>标签,本身不会渲染,只是做包裹。

官方API地址:https://cn.vuejs.org/v2/guide/render-function.html#%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BB%84%E4%BB%B6

我们可以把函数式组件想像成组件里的一个函数,输入参数是渲染上下文(render context),返回值是渲染好的HTML

对于函数式组件,可以这样定义:

  • Stateless(无状态):组件自身是没有状态的
  • Instanceless(无实例):组件自身没有实例,也就是没有this,事件只能由父组件传递

例子:

  1. <div id="app">
  2. <smart-list :items=items></smart-list>
  3. </div>

app.vue:

  1.   //当父组件传过来的是空items时
  2. var EmptyList = {template: '<p>Empty list</p>'};
  3. //当父组件传来的items元素为对象类型时
  4. var TableList = 'ul'
  5. // 当父组件定义了isOrdered变量且为true
  6. var UnorderedList = 'ul'
  7.  
  8. //定义组件
  9. Vue.component('smart-list', {
  10. //标记为函数式组件
  11. functional: true,
  12.  
  13. //render函数
  14. render: function (createElement, context) {
  15. // console.log(context)//若不理解可以打印出来context来看看里面都有些什么东西
  16.  
  17. //规定组件的渲染规则
  18. function appropriateListComp() {
  19. //获取父组件传来的数据
  20. var items = context.props.items;
  21.  
  22. //若空,则返回前面定义的emptylist
  23. if (items.length === 0) return EmptyList;
  24. //若为对象
  25. if (typeof items[0] === 'object') return TableList;
  26. //其他
  27. return UnorderedList
  28. }
  29.  
  30. //生成模板
  31. return createElement(
  32. //模板标记为渲染规则函数返回值
  33. appropriateListComp(),
  34. //模板子元素,返回一个数组
  35. Array.apply(null, {length: context.props.items.length}).map(function (value, index) {
  36. return createElement('li',context.props.items[index].name)
  37. })
  38. )
  39. },
  40. props: {
  41. items: {
  42. type: Array,
  43. required: true
  44. },
  45. isOrdered: Boolean
  46. }
  47. });
  48. new Vue({
  49. el: '#app',
  50. data:{
  51. items:[
  52. {
  53. name:'a',
  54. id:0
  55. },
  56. {
  57. name:'b',
  58. id:1
  59. },
  60. {
  61. name:'c',
  62. id:2
  63. }
  64. ]
  65. }
  66. })

最终浏览器渲染结果:

  1. <div id="app">
  2. <ul>
  3. <li>a</li>
  4. <li>b</li>
  5. <li>c</li>
  6. </ul>
  7. </div>

再举一个例子,代码目录结构如下:

render-page:

  1. <template>
  2. <div>
  3. <list :list="list" :render="renderFunc"></list>
  4. </div>
  5. </template>
  6. <script>
  7. import List from "_c/list";
  8. export default {
  9. data() {
  10. return {
  11. list: [
  12. {
  13. name: "张三"
  14. },
  15. {
  16. name: "李四"
  17. }
  18. ]
  19. };
  20. },
  21. components: {
  22. List
  23. },
  24. methods: {
  25. renderFunc: function(h, name) {
  26. return h("i", {
  27. style: {
  28. color: "pink"
  29. }
  30. },name);
  31. }
  32. }
  33. };
  34. </script>

router.js:

  1. import Home from "@/views/Home.vue";
  2.  
  3. export default [
  4. {
  5. path: "/",
  6. alias: "/home_page",
  7. name: "home", //加上name属性 命名路由
  8. component: Home,
  9. props: route => ({
  10. food: route.query.food
  11. }),
  12. beforeEnter: (to, from, next) => {
  13. // if (from.name === "about") alert("这是从about来的");
  14. // else alert("这不是从about来的");
  15. next();
  16. }
  17. },
  18. {
  19. path: '/render_page',
  20. name: 'render_page',
  21. component: () => import('@/views/render-page.vue')
  22. }
  23. {
  24. path: "*",
  25. component: () => import("@/views/error_404.vue")
  26. }
  27. ];

list/index.js:

  1. import List from "./list.vue";
  2. export default List;

list/list.vue:

  1. <template>
  2. <ul>
  3. <li v-for="(item,index) in list" :key="`item_${index}`">
  4. <span v-if="!render">{{item.name}}</span>
  5. <render-dom v-else :render-func="render" :name="item.name"></render-dom>
  6. </li>
  7. </ul>
  8. </template>
  9. <script>
  10. import RenderDom from "_c/render-dom";
  11. export default {
  12. name: "List",
  13. components: {
  14. RenderDom
  15. },
  16. props: {
  17. list: {
  18. type: Array,
  19. default: () => []
  20. },
  21. render: {
  22. type: Function,
  23. default: () => {}
  24. }
  25. }
  26. };
  27. </script>

render-dom.js:

  1. export default {
  2. functional: true,
  3. // Props 是可选的
  4. props: {
  5. name: String,
  6. renderFunc: Function
  7. },
  8. // 为了弥补缺少的实例,提供第二个参数作为上下文
  9. render: (h, ctx) => {
  10. return ctx.props.renderFunc(h, ctx.props.name);
  11. }
  12. };

运行效果:

JSX(可参考https://juejin.im/post/5affa64df265da0b93488fdd):

什么是JSX:

JSX就是Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚拟DOM。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。

将刚才的例子中的render-page.vue中的render函数改为jsx语法(它可以让我们回到更接近于模板的语法上):

  1. <template>
  2. <div>
  3. <list :list="list" :render="render"></list>
  4. </div>
  5. </template>
  6. <script>
  7. import List from "_c/list";
  8. export default {
  9. data() {
  10. return {
  11. list: [
  12. {
  13. name: "张三"
  14. },
  15. {
  16. name: "李四"
  17. }
  18. ]
  19. };
  20. },
  21. components: {
  22. List
  23. },
  24. methods: {
  25. render: function(h, name) {
  26. // return h("i", {
  27. // style: {
  28. // color: "pink"
  29. // }
  30. // },name);
  31. return (
  32. ////绑定事件需要用on前缀
  33. <i on-click={this.handlerClick} style={{color:'pink'}}>{name}</i>
  34. );
  35. },
  36. handlerClick(event){
  37. console.log(event);
  38. }
  39. }
  40. };
  41. </script>

在JSX中使用组件(使用和上一个例子同样的目录结构):

注意在render或者JSX中写的组件是不需要在components中注册的。

render-page.vue:

  1. <template>
  2. <div>
  3. <list :list="list" :render="render"></list>
  4. </div>
  5. </template>
  6. <script>
  7. import List from "_c/list";
  8. import CountTo from "_c/count-to";
  9. export default {
  10. data() {
  11. return {
  12. list: [
  13. {
  14. number: 100
  15. },
  16. {
  17. number: 200
  18. }
  19. ]
  20. };
  21. },
  22. components: {
  23. List
  24. },
  25. methods: {
  26. render: function(h, number) {
  27. return (
  28. //绑定事件需要用on-开头 绑定原生事件用nativeOn-开头
  29. <CountTo nativeOn-click={this.nativeHandlerOn} on-on-animation-end={this.handlerEnd} endVal={number} />
  30. );
  31. },
  32. handlerClick(event) {
  33. console.log(event);
  34. },
  35. handlerEnd() {
  36. console.log("End!!!");
  37. },
  38. nativeHandlerOn(){
  39. console.log("这是原生事件");
  40. }
  41. }
  42. };
  43. </script>

list.vue:

  1. <template>
  2. <ul>
  3. <li v-for="(item,index) in list" :key="`item_${index}`">
  4. <span v-if="!render">{{item.number}}</span>
  5. <render-dom v-else :render-func="render" :number="item.number"></render-dom>
  6. </li>
  7. </ul>
  8. </template>
  9. <script>
  10. import RenderDom from "_c/render-dom";
  11. export default {
  12. name: "List",
  13. components: {
  14. RenderDom
  15. },
  16. props: {
  17. list: {
  18. type: Array,
  19. default: () => []
  20. },
  21. render: {
  22. type: Function,
  23. default: () => {}
  24. }
  25. }
  26. };
  27. </script>

render-dom.js:

  1. export default {
  2. functional: true,
  3. // Props 是可选的
  4. props: {
  5. number: Number,
  6. renderFunc: Function
  7. },
  8. // 为了弥补缺少的实例,提供第二个参数作为上下文
  9. render: (h, ctx) => {
  10. return ctx.props.renderFunc(h, ctx.props.number);
  11. }
  12. };

效果图:

作用域插槽

作用域插槽就是父组件在调用子组件的时候给子组件传了一个插槽,这个插槽为作用域插槽,该插槽必须放在template标签里面,同时声明从子组件接收的数据放在一个自定义属性内,并定义该数据的渲染方式。适合的场景是至少包含三级以上的组件层级,是一种优秀的组件化方案!

render-page.vue:

  1. <template>
  2. <div>
  3. <list :list="list">
  4. <count-to slot-scope="count" :endVal="count.number"></count-to>
  5. </list>
  6. </div>
  7. </template>
  8. <script>
  9. import List from "_c/list";
  10. import CountTo from "_c/count-to";
  11. export default {
  12. data() {
  13. return {
  14. list: [
  15. {
  16. number: 100
  17. },
  18. {
  19. number: 200
  20. }
  21. ]
  22. };
  23. },
  24. components: {
  25. List,
  26. CountTo
  27. },
  28. methods: {
  29. }
  30. };
  31. </script>

list.vue:

  1. <template>
  2. <ul>
  3. <li v-for="(item,index) in list" :key="`item_${index}`">
  4. <!-- <span v-if="!render">{{item.number}}</span>
  5. <render-dom v-else :render-func="render" :number="item.number"></render-dom> -->
  6. <slot :number="item.number"></slot>
  7. </li>
  8. </ul>
  9. </template>
  10. <script>
  11. import RenderDom from "_c/render-dom";
  12. export default {
  13. name: "List",
  14. components: {
  15. RenderDom
  16. },
  17. props: {
  18. list: {
  19. type: Array,
  20. default: () => []
  21. },
  22. render: {
  23. type: Function,
  24. default: () => {}
  25. }
  26. }
  27. };
  28. </script>

Render渲染函数和JSX的更多相关文章

  1. Vue之render渲染函数和JSX的应用

    一.模板缺陷 模板的最大特点是扩展难度大,不易扩展.可能会造成逻辑冗余 <Level :type="1">哈哈</Level> <Level :typ ...

  2. Vue.js 2.x render 渲染函数 & JSX

    Vue.js 2.x render 渲染函数 & JSX Vue绝大多数情况下使用template创建 HTML.但是比如一些重复性比较高的场景,需要运用 JavaScript 的完全编程能力 ...

  3. Vue.js 渲染函数, JSX(未掌握,未学完)

    渲染函数 , JSX(没完成学习) 基础: 实例属性:vm.$slots default 属性包括了所有没有被包含在具名插槽中的节点. 渲染函数: render: function(createEle ...

  4. Vue躬行记(7)——渲染函数和JSX

    除了可通过模板创建HTML之外,Vue还提供了渲染函数和JSX,前者的编码自由度很高,后者对于开发过React的人来说会很熟悉.注意,Vue的模板最终都会被编译成渲染函数. 一.渲染函数 虽然在大部分 ...

  5. 理解Vue中的Render渲染函数

    理解Vue中的Render渲染函数 VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数.比如如下我想要实现 ...

  6. 基于VueJS的render渲染函数结合自定义组件打造一款非常强大的IView 的Table

    基于VueJS的render渲染函数结合自定义组件打造一款非常强大的IView 的Table https://segmentfault.com/a/1190000015970367

  7. vue render 渲染函数

    vue render 渲染函数 经常看到使用render渲染函数的示例,而且在一些特殊情况下,确实更好使用,可以更加有效地细分组件,因而借助vue-element-admin来学习一波 render函 ...

  8. 必备技能三、render渲染函数

    Vue 推荐使用在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template ...

  9. 【js】vue 2.5.1 源码学习 (十一) 模板编译compileToFunctions渲染函数

    大体思路(九) 本节内容: 1. compileToFunctions定位 1. compileToFunctions定位 ==> createCompiler = createCompiler ...

随机推荐

  1. 《深入理解Java虚拟机》笔记02 -- 垃圾收集算法

    1. 标记 - 清除算法 先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象.它是最基础的收集算法.其他收集算法都是根据其思路,改进其不足之处. 缺点:1) 标记和清除两个阶段的效率都不 ...

  2. uoj#348/洛谷P4221 [WC2018]州区划分(FWT)

    传送门(uoj) 传送门(洛谷) 全世界都会子集卷积就咱不会--全世界都在写\(FMT\)就咱只会\(FWT\)-- 前置芝士 或运算\(FWT\)或者\(FMT\) 左转洛谷模板区,包教包会 子集卷 ...

  3. IT兄弟连 JavaWeb教程 AJAX定义以及解决的问题

    Ajax是"Asynchronous JavaScript And XML"的缩写(即:异步的JavaScript和XML),是一种实现无页面刷新获取服务器数据的混合技术,Ajax ...

  4. Python学习笔记(字典)

    今天学习一个python中的基本类型--字典(dictionary) 字典这种数据结构有点像我们平常用的通讯录,有一个名字和这个名字对应的信息.在字典中,名字叫做“键”,对应的内容信息叫做“值”.字典 ...

  5. 剑指Offer的学习笔记(C#篇)-- 用两个栈实现队列

    题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 一 . 概念! 首先要理解栈和队列的概念. 1. 栈:咱可以简单的把栈理解成装羽毛球的球桶.或者我们吃的 ...

  6. PHP闭包和匿名函数

    概念 闭包和匿名函数在PHP5.3.0中被引入. 闭包 闭包是指创建时封装周围环境的函数.即使闭包所在的环境不存在了,闭包中封装的状态依然存在.这个概念很难理解,不过没关系,继续看下去就会明白了. 匿 ...

  7. Jeasyui的datagrid前端分页要点

    Jeasyui的分页有两种方式: 1. 服务器端分页,是真正的分页,datagridview的pager会自动把pageSize和pageNum传到后台,后台根据根据pageSize和pageNum构 ...

  8. Linux操作学习笔记1

    Linux只有一个根目录/,所有的文件和设备都当成是文件进行管理: pwd 打印当前工作目录 (print working directory) whoami ls  列出当前目录面的文件 ls -l ...

  9. CSS——三种页面引入方法

    目的:为了把样式和内容分开,并且使网页元素更加丰富,引入了CSS CSS页面引入有三种方式: 1)内联式:比较不常用,因为内容和样式仍然在一起,不方便.示例: <!DOCTYPE html> ...

  10. reaver 破解wifi

    1. 无线网卡设置为监控模式 airmon-ng start wlan0 2. 获取附近路由信息 airodump-ng wlan0mon 3. 使用reaver破解wifi reaver -i wl ...