Vue2中的render函数

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

在Vue2中,render函数是一个可选的、用于生成虚拟DOM的特殊函数。它是Vue实例的一个选项,允许开发者使用JavaScript编写模板,而不是使用HTML模板。render函数接收一个h函数(h函数是createElement的别名。很多人喜欢用createElement,形参不过是个名称而已)作为参数,该函数用于创建虚拟节点(VNode)。

下面是一个render函数简单示例:

javascript 复制代码
render(h) {
  return h('h1', 'Hello, Vue!')
}

上面是一个简单写法,完整来说,h函数接受三个参数:

第一个参数:可以是字符串(表示HTML标签名或组件名)、组件对象或函数。如果是自定义组件,需要确保组件已经在当前实例或全局注册。

第二个参数:属性对象,包含传递给子组件的props、attrs、class、style等。

第三个参数:子节点,可以是字符串、数组或对象。

当第一个参数为HTML标签名的时候,常用配置如下:

javascript 复制代码
const vnode = h('div', {
  id: 'my-id', // 设置id属性
  class: 'my-class', // 设置class属性
  style: { color: 'red' }, // 设置内联样式
  onClick: function() { // 设置点击事件处理程序
    console.log('Clicked!');
  }
}, [
  h('p', { class: 'text' }, 'Hello, World!') // 子节点
]);

当第一个参数为组件名称时,配置如下:

javascript 复制代码
const vnode = h('my-component', {
  // 组件的类名  使用同 :class  语法
  class: {
    aaa: true
  },
  // 组件的内联样式  使用同 :style  语法
  style: {
    color: 'blue'
  },
  // 一个对象,包含组件所需的属性。这些属性将被传递给组件,并在组件内部作为props进行访问。
  props: {
    msg: 'Hello, World!',
  },
  //一个对象,包含组件的非prop属性(例如,class、style等)。这些属性将被添加到组件的根元素上。
  attrs: {
    class: 'my-class',
    style: { color: 'red' }
  },
  // 一个对象,包含组件的事件处理程序。
  on: {
    click() {
      console.log('Clicked!!!')
    }
  },
  // 一个对象,包含组件的原生事件处理程序。与on类似,但用于监听原生DOM事件。
  nativeOn: {
    click() {
      console.log('Clicked!!!')
    }
  },
  // 一个对象,包含组件的DOM属性。
  domProps: {
    innerHTML: 'Hello, World!'
  },
  // 一个对象,包含组件的作用域插槽。
  scopedSlots: {
    default: () => h('h1', null, '我是标题1')
  },
  // 一个字符串或数组,表示组件的插槽内容
  slot: 'slot container',
  // 一个字符串或数字,表示组件的唯一标识符。
  key: 'unique-key',
  // 一个字符串,表示组件的引用标识符。
  ref: 'myComp',
  // 一个函数,返回组件实例的数据对象。
  data() {
    return {
      name: 'wft'
    }
  },
  // 一个对象,包含组件的指令。
  directives: [{ name: 'my-directive', value: 'Hello, World!' }],
  // 一个对象,包含组件的生命周期钩子。
  hooks: {
    created() {
      console.log('created!!')
    },
    mounted() {
      console.log('mounted!!')
    }
  },
  // 一个布尔值,表示是否将父组件的属性继承到子组件。
  inheritAttrs: true,
  // 一个字符串,表示组件的真实标签名。这在渲染组件时非常有用,因为它允许Vue跳过验证过程。
  is: 'my-component'
}, {
  default: () => h('p', null, '我是默认插槽')
});

我们在给子组件传递数据的时候,也就是父传子,一般写在props中, 其实也可以写在attrs中,如果写在attrs中,我们也可以在子组件中props中接受attrs中的变量,如果props中没写的变量都会在attrs中,我们在组件中通过this.$attrs中可以拿到。

下面是一个示例:

先使用render函数封装一个组件,注意写了render函数就不要写template了,不然render函数不起作用

@/components/BasicRender.vue

javascript 复制代码
<script>
import { deepClone } from '@/utils'
export default {
  props: {
    tag: {
      type: String,
      default: 'div'
    },
    option: {
      type: Object,
      default: () => null
    },
    children: {
      type: [String, Array, Object],
      default: ''
    }
  },
  render(h) {
    const opt = deepClone(this.option)
    console.log(opt, 'opt-->.')
    return h(this.tag, opt, this.children)
  }
}
</script>

上面是一个vue组件,也可以写一个.js文件,写render函数,那么它也可以跟组件一样使用(注册使用):

@/components/Render.js

javascript 复制代码
import { deepClone } from '@/utils'
export default {
  props: {
    tag: {
      type: String,
      default: 'div'
    },
    option: {
      type: Object,
      default: () => null
    },
    children: {
      type: [String, Array, Object],
      default: ''
    }
  },
  render(h) {
    const opt = deepClone(this.option)
    console.log(opt, 'opt  对象 obj -->.')
    return h(this.tag, opt, this.children)
  }
}

然后是main.vue,引入封装的render组件

javascript 复制代码
<template>
  <div class="wft-main">
    <BasicRender
      :tag="tag"
      :option="option"
      :children="children"
    />
  </div>
</template>
<script>
// import BasicRender from '@/components/Render'
import BasicRender from '@/components/BasicRender'
export default {
  data() {
    return {
      // tag: 'div',
      // option: {
      //   id: 'WFT',
      //   class: 'wft',
      //   style: {
      //     border: '1px solid red',
      //     width: '350px',
      //     height: '350px',
      //     display: 'flex',
      //     justifyContent: 'center',
      //     alignItems: 'center'
      //   },
      //   onClick() {
      //     console.log('onClicked!!!')
      //   },
      //   attrs: {
      //     msg: '456 msg'
      //   }
      // },
      // children: '呵呵呵'

      tag: 'G1',
      option: {
        class: {
          'G1-class': true
        },
        style: {
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'center',
          alignItems: 'center'
        },
        props: {
          title: 'wwwfffttt',
          age: 18,
          info: {
            name: 'wft'
          }
        },
        attrs: {
          customData: {
            id: '0000',
            name: 'JAY'
          }
        },
        scopedSlots: {
          default: () => (<BasicRender tag={'h1'} children={'66611'} />),
          content: () => '我是content'
        }
      },
      children: {
        default: '666',
        content: '我是content插槽内容'
      }
    }
  },
  components: { BasicRender }
}
</script>
<style scoped>
.wft-main {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center
}
</style>

这是加载组件G1,注意:我们加载的组件一定是引入、注册之后的,我这里全局注册了,

然后是G1组件:

javascript 复制代码
<template>
  <div class="wft-w-h-100">
    <slot></slot>
    <h1>我是G1 全局组件</h1>
    <h3>{{ title }}--{{ age }}--{{ info }}</h3>
    <slot name="content"></slot>
  </div>
</template>
<script>
export default {
  data() {
    return {

    }
  },
  props: {
    customData: {
      type: Object,
      default: () => ({})
    },
    title: {
      type: String,
      default: ''
    },
    age: {
      type: Number,
      default: 0
    },
    info: {
      type: Object,
      default: () => ({})
    }
  }
}
</script>
<style scoped>
.wft-w-h-100 {
  width: 100%;
  height: 100%;
}
</style>

下面是运行的效果图:

相关推荐
F2E_Zhangmo8 分钟前
vue长列表,虚拟滚动
前端·javascript·vue.js
睿智的海鸥19 分钟前
html+css+js气泡弹窗
javascript·css·html
安冬的码畜日常19 分钟前
【D3.js in Action 3 精译】1.2.2 可缩放矢量图形(三)
开发语言·前端·javascript·信息可视化·数据可视化
睿智的海鸥37 分钟前
html css js做的在线签到例子
javascript·css·html
LiamHong_41 分钟前
简单了解 HTTP 请求方法
前端·后端·http·学习方法·web
蓝胖子的多啦A梦1 小时前
【问题已解决】Vue管理后台,点击登录按钮,会发起两次网络请求(竟然是vscode Compile Hero编译插件导致的)
前端·vue.js·vscode
Lsx-codeShare1 小时前
Nginx Http缓存的必要性!启发式缓存有什么弊端?
前端·javascript·nginx·http·缓存·webpack
南七小僧1 小时前
Android Studio 解决AAPT: error: file failed to compile
前端·javascript·vue.js
陈琦鹏1 小时前
zoom缩放问题(关于ElementPlus、Echarts、Vue3draggable等组件偏移问题)
前端·javascript·echarts
盏茶作酒1 小时前
解决expand-change第一次展开无数据显示与实现
开发语言·前端·javascript