Vue render 函数和JSX语法的使用
基本使用
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。
让我们深入一个简单的例子,这个例子里 render
函数很实用。假设我们要根据父组件传过来的数据决定显示哪个标签:
父组件:
<template>
<div id="app">
<level type="1">hello world</level>
<level type="2">hello world</level>
<level type="3">hello world</level>
<level type="4">hello world</level>
</div>
</template>
<script>
import Level from './components/Level'
export default {
name: 'App',
components: {
Level
}
}
</script>
Level组件:
<template>
<div>
<h1 v-if="type == 1"><slot></slot></h1>
<h2 v-else-if="type == 2"><slot></slot></h2>
<h3 v-else-if="type == 3"><slot></slot></h3>
<h4 v-else-if="type == 4"><slot></slot></h4>
</div>
</template>
<script>
export default {
name: 'Level',
props:{
type: String || Number
}
}
</script>
Level组件根据父组件穿过来的type来判断显示h1、h2、h3等标签,v-if 可以说用到了"极致",而且写了很多个冗余的slot
使用render函数和JSX语法来改写上面
Level.js文件
export default {
props:{
type: String | Number
},
methods:{
handleClick(e){
console.log(e.target)
},
},
data(){
return {msg:'zf'}
},
render(h){ //运行时
// h('h' + this.type,{},[this.$slots.default])
let tag = 'h' + this.type
return <tag>
<span value={tag} onClick={this.handleClick}>{this.$slots.default}</span>
{this.msg}
</tag>
}
}
省去了很多冗余代码,页面一下清爽了很多
用JSX语法实现v-model、v-if、v-for语法
v-model:
export default {
methods:{
handleInput(e){
this.msg = e.target.value
}
},
data(){
return {msg:'zf'}
},
render(){ //运行时return
{/* 实现v-model */}
<input type="text" value={ this.msg} onInput={this.handleInput}></input>
{this.msg}
}
}
给input框顶一个value属性 一个input事件onInput,传值和监听事件改变值。
v-if: 三元表达式
render(){
return (
<div>
{this.show?'好':'不好'}
</div>
)
}
简单的语法可以用三元表达式
复杂的语法还是要用if/else来判断
render(){
let ifText
if(this.show){
ifText=<p>好</p>
}else {
ifText=<p>不好</p>
}
return (
<div>
{ifText}
</div>
)
}
v-for:以menu菜单为例
import elMenu from "./el-menu";
import elMenuItem from "./el-menu-item";
import elSubmenu from "./el-submenu";
export default {
//父组件传过来的数据
props:{
data:{
type: Array,
default:() => {}
}
},
data(){
return {
menudata:[
{title: '根1', id: 1},
{title: '根2', id: 2, children: [
{
title:'根2-1', id: 21,
children: [
{title: '根2-1-1', id: 211},
{title: '根2-1-2', id: 212}
]
}
]
},
{title: '根3', id: 3},
{title: '根4', id: 4,children: [
{title: '根4-1', id: 41}
]}
]
}
},
render() {
let renderChildren = (data) => {
return data.map(child =>{
return child.children ? //判断是否有孩子
//有孩子渲染elSubmenu
<elSubmenu>
<div slot="title">{child.title}</div>
{renderChildren(child.renderChildren)}
</elSubmenu> : //没有孩子渲染elMenuItem
<elMenuItem></elMenuItem>
})
}
return <elMenu>
{/* 循环遍历孩子 显示哪一个 */}
{renderChildren(this.data)}
</elMenu>
}
}
用自定义组件
导入进来,不用再在components属性声明了,直接写在jsx中
<script>
import HelloWolrd from './HelloWorld'
export default {
name: "item",
render(){
return (
<HelloWolrd/>
)
}
}
</script>
事件,class,style,ref等的绑定方式
render (h) {
return (
<div
// normal attributes or component props.
id="foo"
// DOM properties are prefixed with `domProps`
domPropsInnerHTML="bar"
// event listeners are prefixed with `on` or `nativeOn`
onClick={this.clickHandler}
nativeOnClick={this.nativeClickHandler}
// other special top-level properties
class={{ foo: true, bar: false }}
style={{ color: 'red', fontSize: '14px' }}
key="key"
ref="ref"
// assign the `ref` is used on elements/components with v-for
refInFor
slot="slot">
</div>
)
}
上面有个地方需要注意,当给自定义组件绑定事件时用nativeOnClick,而模板格式是用@click.native
在实际开发中并不是全部都有renderJSX语法好或者全都用template好,而是在需要的地方两者结合使用,效果会更好。
不积跬步无以至千里