虽然在写组件的时候可以避开命名以on开头,但是在使用第三库的时候,如果遇到了该如何处理呢?比如Element组件Upload很多钩子都是以on开头。 下面提供两种解决办法:
1.使用展开
<el-upload {...{ props: { onPreview: this.handlePreview } }} />
使用propsXx
<el-upload propsOnPreview={this.handlePreview} />
推荐使用第二种方式,写起来要简单些。
复杂逻辑条件判断
在模板语法中可以使用v-if、v-else-if和v-else来做条件判断。在jsx中可以通过?:三元运算符(Ternary operator)运算符来做if-else判断:
const Demo = () => isTrue ? <p>True!</p> : null
然后可以利用&&运算符的特性简写为:
const Demo = () => isTrue && <p>True!</p>
对于复杂的条件判断,例如:
const Demo = () => ( <div> {flag && flag2 && !flag3 ? flag4 ? <p>Blash</p> : flag5 ? <p>Meh</p> : <p>hErp</p> : <p>Derp</p> } </div> )
可以采用两种方式来降低判断识别的复杂度
下面是使用IIFE通过内部使用if-else返回值来优化上述问题:
const Demo = () => ( <div> { (() => { if (flag && flag2 &&!flag3) { if (flag4) { return <p>Blah</p> } else if (flag5) { return <p>Meh</p> } else { return <p>Herp</p> } } else { return <p>Derp</p> } })() } </div> )
还可以使用do表达式,但是需要插件@babel/plugin-proposal-do-expressions的转译来支持,
const Demo = () => ( <div> { do { if (flag1 && flag2 && !flag3) { if (flag4) { <p>Blah</p> } else if (flag5) { <p>Meh</p> } else { <p>Herp</p> } } else { <p>Derp</p> } } } </div> )
再就是一种比较简单的可选办法,如下:
const Demo = () => { const basicCondition = flag && flag1 && !flag3; if (!basicCondition) return <p>Derp</p> if (flag4) return <p>Blah</p> if (flag5) return <p>Meh</p> return <p>Herp</p> }
最后一种使用jsx插件的就不详述和举例了,有兴趣的可以直接查看文档。
组件的传值
在单个jsx文件中可以写很多函数式组件来切分更小的粒度,例如之前的文章Vue后台管理系统开发日常总结__组件PageHeader,组件的形态有两种,一种是普通标题,另一种是带有选项卡的标题,那么在写的时候就可以这样写:
render() { // partial html const TabHeader = ( <div></div> ) // function partial const Header = () => ( <div></div> ) <div> {this.withTab ? TabHeader : <Header/>} </div> }
注意在拆分的时候,如果不需要做任何判断可以纯粹是HTML片段赋值给变量,如果需要条件判断就使用函数式组件的方式来写。需要注意的是由于render函数会多次被调用,写的时候注意一下对性能的影响,目前能力有限这方面就不作展开了。
既然使用函数式组件,那么同样可以在函数中传递参数了,参数是一个对象中,包含了以下属性
children # VNode数组,类似于React的children data # 绑定的属性 attrs # Attribute domProps # DOM property on # 事件 injections # 注入的对象 listeners: # 绑定的事件类型 click # 点击事件 ... parent # 父组件 props # 属性 scopedSlots # 对象,作用域插槽,使用中发现作用域插槽也挂在这个下面 slots # 函数,插槽
虽然可以在函数式组件中传参数、事件、slot但是个人觉得不建议这样做,反而搞复杂了。
render() { const Demo = props => { return ( <div> <h3>Jsx中的内部组件 { props.data.title }</h3> { props.children } <br /> { props.scopedSlots.bar() } </div> ) } return ( <div> <Demo title="test" attrsA="a" domPropsB="b" onClick={this.demo}> <h3>我是Children</h3> <template slot="bar"> <p>我是Slot内容</p> </template> </Demo> </div> ) }
上面的示例最终生成的HTML中会将<template>的内容转换为#document-fragment。
总结