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

render 基本写法

export default {
name: 'renderTest',
data() {},
render: (createElement) => {
return createElement(tag, data, context)
},
props: {},
methods: {},
created () {}
...
}

Vue 通过建立一个虚拟 DOM 对真实 DOM 发生的变化保持追踪。

render函数提供了一个参数createElement(可以简写为h), 用来生成DOM, 其有三个参数:

  • 第一个参数: {String | Object | Function}, 必要参数,一个 HTML 标签字符串,组件选项对象,或者一个返回值类型为 String/Object 的函数
  • 第二个参数: {Object},可选参数,一个包含模板相关属性的数据对象,这样,您可以在 template 中使用这些属性。
  • 第三个参数: {String | Array},可选参数, 子节点 (VNodes),由 createElement() 构建而成, 或使用字符串来生成“文本节点”。

数据对象详解

{
// 和`v-bind:class`一样的 API
'class': {
foo: true,
bar: false
},
// 和`v-bind:style`一样的 API
style: {
color: 'red',
fontSize: '14px'
},
// 正常的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 props
props: {
myProp: 'bar'
},
// DOM 属性
domProps: {
innerHTML: 'baz'
},
// 事件监听器基于 `on`
// 所以不再支持如 `v-on:keyup.enter` 修饰器
// 需要手动匹配 keyCode。
on: {
click: this.clickHandler
},
// 仅对于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意,您无法对绑定中的 `oldValue` 赋值
// Vue 会为您持续追踪
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// Scoped slots in the form of
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其他组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其他特殊顶层属性
key: 'myKey',
ref: 'myRef'
}

v-if 、 v-for 与 v-model

render 函数中没有与v-if 、 v-for 、v-model 相应的 api, 必须自己来实现相应的逻辑

render: function (createElement) {
if (this.items.length) {
return createElement('ul', this.items.map(function (item) {
return createElement('li', item)
}))
} else {
return createElement('p', 'No items found.')
}
}

完整示例

renderTest组件

export default {
name: 'renderTest',
data() {
return {
}
},
render: function (createElement) { return createElement(
'h' + this.level,
{
on: {
click: this.clickHandler
}
},
[
createElement('a', {
attrs: {
href: '##'
}
}, this.$slots.default)
]
)
},
props: {
level: {
type: Number,
required: true
}
},
methods: {
clickHandler () {}
}
}

使用组件

<renderTest :level="1">
<button> Hello world!</button>
</renderTest>

组件中自定义render(函数式组件)

render组件

export default {
name: 'renderTest',
functional: true,
props: {
render: Function,
item: String,
index: Number
},
render: (h, ctx) => {
const params = {
item: ctx.props.item,
index: ctx.props.index
}
return ctx.props.render(h, params)
}
}

我们将组件记为 functional,这意味它无状态(没有 data),无实例(没有 this 上下文)。

在添加 functional: true 之后,组件的 render 函数之间将增加 ctx 参数

组件需要的一切都是通过 ctx 传递,包括:

  • props: 提供 props 的对象
  • children: VNode 子节点的数组
  • slots: slots 对象
  • data: 传递给组件的 data 对象
  • parent: 对父组件的引用

list组件

<template>
<ul class="bs-list left" style="width:200px;">
<li v-for="(item, i) in listDate" class="list-item" :key="i">
<span>{{item}}</span>
<renderTest v-if="renderfun" :item="item" :index="i" :render="renderfun"></renderTest>
</li>
</ul>
</template>
<script>
import renderTest from './renderTest.js'
export default {
name: 'lists',
components: { renderTest },
props: {
listDate: {
type: Array
},
renderfun: {
type: Function,
default() {
return () => false
}
}
}
}
</script>

使用组件

<template>
<div class="text">
<lists :listDate="listDate" :renderfun="renderfun"></lists>
</div>
</template>
<script>
import lists from './lists.vue'
export default {
name: 'text',
components: { lists },
data() {
return {
listDate: [ 'list item 1', 'list item 2', 'list item 3', 'list item 4', 'list item 5' ],
renderfun: (h, ctx) => {
return h('div', {
style: {display: 'inline-block', float: 'right'}
}, [
h('button', {
class: ['btn-primary'],
on: {
click: () => {
this.listDate.splice(ctx.index, 1)
}
}
}, '删除')
])
}
}
}
}
</script>

JSX使用

安装babel依赖

npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-env --save-dev

.babelrc 文件配置

{
"presets": ["env"],
"plugins": ["transform-vue-jsx"]
}

书写格式

render (h) {
return (
<div
// 普通的属性
id="foo"
// DOM 属性,添加前缀`domProps`
domPropsInnerHTML="bar"
// 事件监听,添加前缀 `on` or `nativeOn`
onClick={this.clickHandler}
nativeOnClick={this.nativeClickHandler}
// 其他属性
class={{ foo: true, bar: false }}
style={{ color: 'red', fontSize: '14px' }}
key="key"
ref="ref"
slot="slot">
</div>
)
}

实例

export default {
name: 'renderJSX',
data() {
return {
num: 1
}
},
render() {
const data = {
class: ['b', 'c']
}
return (<div class = 'div'>
<span>123</span>
<button onClick={this.clickHandler} class='btn-primary'>btn</button>
<span class='a' {...data}>{this.num}</span>
</div>)
},
props: {
level: {
type: Number
}
},
methods: {
clickHandler() {
this.num++
console.log('clickHandler')
}
},
created() {}
}

https://vuefe.cn/v2/guide/render-function.html

https://github.com/vuejs/babel-plugin-transform-vue-jsx

vue之render基本书写方法的更多相关文章

  1. Vue2.x源码学习笔记-Vue实例的属性和方法整理

    还是先从浏览器直观的感受下实例属性和方法. 实例属性: 对应解释如下: vm._uid // 自增的id vm._isVue // 标示是vue对象,避免被observe vm._renderProx ...

  2. 关于Vue的Render的讲解

    首先我们传统的对于DOM的操作基本上都是通过js直接的获取一个节点,然后对DOM进行增加或者是删除.而Vue的Render这个函数是通过js虚拟的添加dom节点,然后虚拟的添加到html节点上去. 算 ...

  3. vue插件开发的两种方法:以通知插件toastr为例

    方法一: 1.写插件: 在 src 文件夹下面建 lib 文件夹用于存放插件,lib 文件夹下再建toastr文件夹,在toastr文件夹下新建 toastr.js 和 toastr.vue两个文件. ...

  4. Vue(十二)vue实例的属性和方法

    vue实例的属性和方法 1. 属性 vm.$el vm.$data vm.$options vm.$refs <!DOCTYPE html> <html lang="en& ...

  5. 在Vue中关闭Eslint 的方法

    在vue项目中关闭ESLint方法:找到 webpack.base.conf.js 将这些代码注释掉, { test: /\.(js|vue)$/, loader: 'eslint-loader', ...

  6. vue解决遮罩层滚动方法

    vue 遮罩层阻止默认滚动事件 在写移动端页面的时候,弹出遮罩层后,我们仍然可以滚动页面. vue中提供 @touchmove.prevent 方法可以完美解决这个问题 <div class=& ...

  7. vue实例的属性和方法

    vue实例的属性和方法 1. 属性 vm.$el #指定要绑定的元素 vm.$data #Vue 实例的数据对象 vm.$options #获取自定义属性的值 new Vue({ customOpti ...

  8. Vue把父组件的方法传递给子组件调用(评论列表例子)

    Vue把父组件的方法传递给子组件调用(评论列表例子) 效果展示: 相关Html: <!DOCTYPE html> <html lang="en"> < ...

  9. html select options & vue h render

    html select options & vue h render https://developer.mozilla.org/en-US/docs/Web/HTML/Element/opt ...

随机推荐

  1. 换行符\n和回车符\r

    问题始于社区的一个帖子,楼主的问题如下: “在c语言中,对一个不知道大小的文件进行读操作,我用fread()将文件的内容先放到一个缓存区,然后将缓存区中的内容打印出来, 缓存区中的内容和文件中的内容不 ...

  2. @RequestMapping注解

    Spring MVC中用于参数绑定的注解有很多,都在org.springframework.web.bind.annotation包中,根据它们处理的request的不同内容部分可以分为四类(主要讲解 ...

  3. mysql将查询出来的一列数据拼装成一个字符串

    使用GROUP_CONCAT函数. SELECT GROUP_CONCAT(查询的字段 separator ',') FROM table

  4. 随机切换IP和UA

    在爬虫爬取过程中,网站会根据我们的IP和UA去确认到底是浏览器操作还是爬虫在操作,所以,为了让爬虫不被网站禁止,随机切换Ip 和UA是很重要的,因为这个类在各个爬虫中经常要用到,所以可以自已维护一份随 ...

  5. Python基础篇(一)

    首先需要从Python的官网下载python的安装程序,下载地址为:www.python.org/downloads.最新的版本为3.4.1,下载和操作系统匹配的安装程序并安装即可. 安装好了后,在开 ...

  6. Vue打包后出现一些map文件

    Vue打包后出现一些map文件的解决办法: 问题: 可能很多人在做vue项目打包,打包之后js中,会自动生成一些map文件,那我们怎么把它去掉不要呢? 1,运行  cnpm run build  开始 ...

  7. SpringMVC之HelloWorld实例

    1.1 Helloworld实例的操作步骤  1. 加入jar包 2. 配置dispatcherServlet 3. 加入Spring配置文件 4. 编写请求处理器 并表示为处理器 5. 编写视图 1 ...

  8. 初探solr搜索

    solr是一个基于lucene的搜索引擎,lucene是一个全文检索引擎的架构.solr在此之上进行了封装完善,变成了一个很流行实用的搜索引擎,可以应对绝大部分的搜索需求.使用搜索引擎有以下几点好处: ...

  9. Ubuntu下的Samba服务器配置

    一. samba的安装: sudo apt-get insall samba 二. 创建共享目录: mkdir /home/phinecos/share sodu chmod 777 /home/ge ...

  10. windows下apache服务器开启压缩和网页缓存

    找到配置文件:http.conf apache开启压缩 一.开启配置,去除下面代码前面的#号LoadModule deflate_module modules/mod_deflate.soLoadMo ...