姿式很重要,末尾有福利html
vue-antd-ui开源了一段时间后,收到了一些反馈,尤为是Form组件上线后,不少用户对JSX的使用感到迷惑和不习惯,为此专门介绍下Vue JSX的使用姿式及注意事项。vue
Form组件的自动收集校验功能须要在JSX下使用,固然若是不须要自动收集校验,你依然可使用templatereact
Vue 推荐在绝大多数状况下使用template来建立你的HTML。然而在一些场景中,你真的须要 JavaScript 的彻底编程的能力,就须要使用render函数,它比 template 更接近编译器。可是复杂的render函数书写异常痛苦,好在官方提供了一个Babel 插件,能够将更接近于模板语法的JSX转译成JavaScript。git
使用过React的同窗对JSX确定不陌生,可是Vue的JSX写法和React的仍是有一些区别。github
React中父子之间传递的全部数据都是属性,即全部数据均挂载在props
下(style, className, children, value, onChange等等)。编程
Vue则否则,仅仅属性就有三种:组件属性props
,普通html属性attrs
,Dom属性domProps
。babel
接下来咱们经过一个示例来详细解释他们的区别:markdown
本文代码可在codesandbox查看运行antd
const ButtonCounter = { name: "button-counter", props: ["count"], methods: { onClick() { this.$emit("change", this.count + 1); } }, render() { return ( <button onClick={this.onClick}>You clicked me {this.count} times.</button> ); } }; export default { name: "button-counter-container", data() { return { count: 0 }; }, methods: { onChange(val) { this.count = val; } }, render() { const { count, onChange } = this; return ( <div> <ButtonCounter style={{ marginTop: "10px" }} count={count} type="button" onChange={onChange} /> <ButtonCounter style={{ marginTop: "10px" }} count={count} type="button" domPropsInnerHTML={`hello ${this.count}.`} onChange={onChange} /> </div> ); } }; 复制代码
组件属性props
:指组件声明的属性,即上述示例中声明的props: ['count']
。dom
普通html属性attrs
: __指组件未声明的属性,即上述示例中的type="button"
,该属性默认会直接挂载到组件根节点的上,若是不须要挂载到根节点,可声明 inheritAttrs: false
。
Dom属性domProps
:指的Dom属性,如上述示例中的innerHTML
,它会覆盖组件内部的children
, 这类属性咱们通常不多使用到。
一样事件属性也分了两种:on
nativeOn
答:正则则则...... 😶,babel-plugin-transform-vue-jsx插件会经过正则匹配的方式在编译阶段将书写在组件上属性进行“分类”。 onXXX的均被认为是事件,nativeOnXXX是原生事件,domPropsXXX是Dom属性。
class,staticClass,style,key,ref,refInFor,slot,scopedSlots
这些被认为是顶级属性,至于咱们属性声明的props,以及html属性attrs,不须要加前缀,插件会将其统一分类到attrs属性下,而后在运行阶段根据是否在props声明来决定属性归属(即属于props
仍是attrs
)。
第1、属性分类是编译阶段进行的分类,那么对于动态属性如何划分分类?
在React中全部属性都是顶级属性,直接使用{...props}
就能够了,可是在Vue中,你须要明确该属性所属的分类,如一个动态属性value和事件change,你可使用以下方式(延展属性)传递:
const dynamicProps = { props: {}, on: {}, } if(haValue) dynamicProps.props.value = value if(hasChange) dynamicProps.on.change = onChange <Dynamic {...dynamicProps} /> 复制代码
固然你能够混合着使用:
<Dynamic {...dynamicProps} style="color: red"/> 复制代码
先别高兴太早,若是你没有深刻使用过Vue JSX,不建议你使用混合方式,由于Vue会对其进行属性合并,至于合并的规则官方也并无详细的文档,文档中有一处示例,我在这再举一个例子:
const dynamicProps2 = { on: { change: onChange2 } }; <Dynamic {...{ on: { change: onChange1 } }} {...dynamicProps2} onChange={onChange3} /> 复制代码
上例中的onChange一、onChange二、onChange3都会触发,而你想要的可能仅仅是onChange3。其它属性的合并规则我就不一一列举了,总之,我不建议你使用混合方式,除非你及你的团队其余小伙伴对其规则了解的足够透彻。
注:理想状况你不该该须要动态属性,在业务开发中也比较少的使用动态属性,但若是你尝试开发一些通用性比较强的组件,就很难逃过动态属性的使用。
第2、若是声明的属性就是onXXX怎么处理?
首先我不建议你这么作,但若是真的须要,你必须明确该属性的分类,以下所示:
<div> <Dynamic value="获取到value,然而并不能获取到onXXX" onXXX="😶" /> <Dynamic {...{ props: { onXXX: "获取到onXXX,但不建议使用" } }} /> </div> 复制代码
第3、函数式组件的props如何处理?
关于函数式组件的相关概念可查看官方文档,文档中有以下一段内容:
注意:在 2.3.0 以前的版本中,若是一个函数式组件想要接受 props,则
props
选项是必须的。在 2.3.0 或以上的版本中,你能够省略props
选项,全部组件上的属性都会被自动解析为 props。
props
和attrs
之间存在着很微妙的关系,在普通组件中,只要明确声明的属性会被划分到props
分类中,剩下的均在attrs
中。而对于函数式组件,只要省略了props
选项,传参时不论是否明确分类,最终context.props
获取到的都是所有属性,若是你须要获取明确的分类状况,能够在context.data
下查看。 总之,在函数式组件中,推荐省略props
选项。
第4、指令是否还可用?
很不幸的告诉你,大多数指令并不能在JSX中使用,对于原生指令,只有v-show
是支持的。 大部分指令在JSX中可使用表达式来替代,如:条件运算符(?:)替代v-if
、array.map
替代v-for
对于自定义的指令,可使用以下方式使用:
const directives = [ { name: 'my-dir', value: 123, modifiers: { abc: true } } ] return <div {...{ directives }}/> 复制代码
更多Vue JSX的知识,能够查看官方文档。
说了那么多,其实只要记住一点,尽可能使用明确分类的方式传递属性,而不是要babel插件帮你分类及合并属性。
最后汇报下vue-antd-ui的进度,目前组件数量48个,相较react版,还有List、TreeSelect、Metion、Carousel没有开发,再过去的一段时间里,咱们更多的去完善组件单元测试,测试覆盖率83%,单测数量610个,接下来测试依然是咱们的主要工做。
质量永远要比数量重要的多。
欢迎star,欢迎pr。
福利环节:
本人参与翻译的React书籍(React Quickly,中文名:快速上手React编程)即将上市,现有样书4本,为了答谢支持vue-antd-ui的用户,使用者可到该issue下按照规范(需截图)回复后私信我地址,邮费自理,先到先得,数量有限,敬请谅解。
相对深刻浅出系列,该书更加适合初学者入门,若是你是Vue开发者,想要快速的学习React及周边技术(Redux、GraphQL、Jest等),我想这本书应该是不二之选。