基本使用
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好,而是在需要的地方两者结合使用,效果会更好。