由于最近接手维护一个基于 ivew 的项目, 新增模块中包含不少自定义功能, 因此大量使用到了 render 函数; 故对其作一下总结...关于 render 函数, 官方文档也作了比较详细的介绍: render 函数: https://cn.vuejs.org/v2/guide... ; 通常组件咱们都是用 template模板的方式去写; 有时候会形成代码上的冗余, 很差扩展.html
在学习 render 函数以前, 最好先了解一下虚拟节点 vNode, 以及虚拟节点树组成的虚拟vDom, 这样会更好的理解 render 函数vue
/* *@describe {渲染函数} *@params {见下方} *@returns {一段VNode} */ createElement函数: 一般写为 h 函数, 也是官方推荐的 h( // {String | Object | Function} => 'p' | 'Select' | (h, p) => {} // 一个 HTML 标签名、组件选项对象,或者 // resolve 了上述任何一种的一个 async 函数。必填项。 'div', // {Object} // 一个与模板中属性对应的数据对象。可选。 { style: { width: '100px' }, }, // {String | Array} // 子级虚拟节点 (VNodes),通常是数组: 由 `h()` 构建而成,参数: ('标签|组件', {attrs}, text) // 也可使用字符串来生成“文本虚拟节点”。可选。 [ '先写一些文字', h('h1', '一则头条'), h(MyComponent, { props: { someProp: 'foobar' } }) ] )
函数式组件 能够看作是组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML字符串
对于函数式组件,能够这样定义:数组
Stateless(无状态):组件自身是没有状态的 Instanceless(无实例):组件自身没有实例,也就是没有this
因为函数式组件中没有this,参数须要靠context来传递; export default { name: 'functional-button', functional: true, render (h, context) { return h('button', '按钮 1 号') } }
由官方文档可知: context 参数以下:less
props:提供全部 prop 的对象 children: VNode 子节点的数组 slots: 一个函数,返回了包含全部插槽的对象 scopedSlots: (2.6.0+) 一个暴露传入的做用域插槽的对象。也以函数形式暴露普通插槽。 data:传递给组件的整个数据对象,做为 createElement 的第二个参数传入组件 parent:对父组件的引用 listeners: (2.3.0+) 一个包含了全部父组件为当前组件注册的事件监听器的对象。这是data.on 的一个别名。 injections: (2.3.0+) 若是使用了 inject 选项,则该对象包含了应当被注入的属性。
<template> <div class="home"> <func-button> hello button </func-button> </div> </template> <script> import FuncButton from '../function-components/func-button' export default { name: 'home', components: { FuncButton } } </script>
如今咱们将这个 func-button.js 组件改造一下, 上面的hello button 文本节点为func-button.js的childern属性(数组|String),咱们可让父组件去控制组件的button按钮内容, 改写以下:dom
// export default { // name: 'functional-button', // functional: true, // render (h, context) { // return h('button', '按钮 1 号') // } // } export default { name: 'funtional-button', functional: true, render (h, { children }) { return h('button', children) } }
code以下:async
<template> <div class="home"> <func-button @click="handleClick"> hello button </func-button> </div> </template> <script> import FuncButton from '../function-components/func-button' export default { name: 'home', components: { FuncButton }, methods: { handleClick () { alert('你点到我了') } } } </script> // func-button组件 export default { functional: true, // 组件的属性集成在data里, 为了简便,咱们能够用 data 来替换下面的 props, listeners等 // 写成 h('button', data, ['hello', ...children]) render (h, { props, listeners, children }) { return h( 'button', { attrs: props, on: { click: listeners.click } }, children ) } }
平时开发仍是多用temlate由于直观简洁,各类指令用着很方便,可是常常写template有时会以为代码看着很冗余,若是想本身控制渲染逻辑好比循,判断等等时咱们就能够考虑使用JSX
关于 JSX 的使用参考ide
<script> export default { name: 'h-title', props: { id: { type: Number, default: 1 } }, render () { const hText = `<h${this.id}>${this.$slots.default[0].text}</h${this.id}>` return <div domPropsInnerHTML={hText}></div> } } </script>
// List.vue 组件 <template> <div> <template v-for="(item, index) in data"> <li :key="index" v-if="!render">{{ item }}</li> <ListItem v-else :key="`a${index}`" :render="render" :item="item" ></ListItem> </template> </div> </template> <script> import ListItem from "./list-item" export default { components: { ListItem }, props: { // 支持自定义渲染 render: { type: Function }, data: { type: Array, default: () => [] } } }; </script> // list-item.js export default { props: { render: { type: Function }, item: { type: String } }, render(h) { // createElement return this.render(h, this.item) } }
// 父组件中 <List :data="['香蕉','苹果','橘子']" :render="render"></List> // 能够渲染你想要的标签和内容 render (h, data) { return <span>{data}</span> }