iview 在今年 7 月 28 号发布了 3.0.0 版本,大版本升级每每意味着功能、接口的大变动。
虽然官网已经有长长的 更新日志,但看起来仍是有些抽象了,
因此我决定作个新旧版本的比较,盘点新版本到底为咱们带来了什么新特性。这一篇给你们讲解的,是一个很经常使用的组件 ——
Button
javascript
新版 Button
有以下新特性:html
to
属性启动ghost
属性,样式上可与其余的 type
值复合Button
的升级相对仍是比较平滑的,须要注意两点:vue
type="ghost"
,但可使用独立的 ghost
属性,因此升级前,建议全局搜索 type="ghost"
的调用default
样式有些不一样旧版本的 Button
组件只单纯包裹了一个 button
标签。
新版本 Button
新增了一个关键属性:to
—— 通常状况下,组件会渲染为 button
标签;
假如 to
有值,则组件会渲染为 a
标签。java
虽然破坏了 Button
的语义,但这个特性还挺方便的,在过去,为了给 a
标签应用 Button
样式,每每须要本身写上 class:ios
<!-- 普通 a 标签 --> <a class="ivu-btn ivu-btn-primary" href="/foo/bar">这是一个 a 连接</a> <!-- router-link --> <router-link class="ivu-btn ivu-btn-primary" to="/foo/bar">这是一个 router-link</router-link>
虽然能够复用按钮样式,但却丧失了 Button
的行为,好比 loading、icon 等。新版本支持连接模式后就没有这个问题了,一样的逻辑,能够写成:git
<Button type="primary" to="/foo/bar">这是一个连接</Button> <!-- 最终渲染为 --> <a class="ivu-btn ivu-btn-primary" href="/foo/bar">这是一个连接</a>
to
属性值支持 string
、object
两种类型,iview 会优先使用 vue-router
的相关函数处理连接跳转;当应用环境中没有 vue-router
时,则会退化成普通的 window.location.href = this.to;
调用。
除了 to
, Button
还新增了 replace
、target
两个属性,用于补充连接的定义。replace
属性语义与 router-link
的 replace 属性的语义相同;target
属性则与 a
标签的 target 属性相同。github
总的来讲,在连接模式下,你能够把 Button
理解为一个阉割版的 router-link
组件。vue-router
ghost
属性幽灵按钮是一个曾经被普遍讨论的话题,如今已是一种很常规的设计了。这种设计指定按钮的背景色必须是透明的,而并无定义字体、边框样式,但旧版本 Button
只支持一种灰色调调的 ghost:api
新版本在这方面作了很大改进,将 ghost
样式独立为一类 class,配合其余 type
类型做为按钮字体、边框颜色的补充,相得益彰,能够看看 iview 官网提供的 示例:antd
多种色值形态的幽灵按钮确实能够大大提升提高实用性。曾经 1.x 版本 的 antd 也把 ghost 做为一种 type 看待,到了2.x 版本 也抽出来作为一个独立特性,iview 这个改进,看来也算是有依有据,亦步亦趋了。
不过,尴尬的是,iview 顺手把 default
的样式也给改了,对于设计有较高要求的团队得注意了:
好了,特性与变动都聊完了,最后咱们来看看代码。 新版 Button
的代码只有 116 行却有很多值得玩味的地方:
新版 Button
的模板是这样的:
<template> <a v-if="to" ...> <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon> <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon> <span v-if="showSlot" ref="slot"><slot></slot></span> </a> <button v-else ...> <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon> <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon> <span v-if="showSlot" ref="slot"><slot></slot></span> </button> </template>
oh,a
与 button
包裹的内容块完彻底全重复了, 彻底如出一辙诶。其实这一块代码能够抽成一个独立的组件,下降重复的。
另外, size
的定义,也挺尴尬的:
... export default { ... props: { ... size: { validator (value) { return oneOf(value, ['small', 'large', 'default']); }, default () { return this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size; } } ... }, ... };
从单个组件看,是没啥毛病,但居然能够在代码里找到 16 处彻底相同的代码,分别为:AutoComplete
、Avatar
、ButtonGroup
、Cascader
、CheckboxGroup
、Checkbox
、ColorPicker
、Picker
、InputNumber
、Input
、RadioGroup
、Radio
、Select
、Spin
、Switch
、Table
...这一块是能够抽成一个 mixin,这错误犯得有点低级了。
旧版本 Button
只是简单包装了 button
标签,因此它的事件处理 很是简单。新版本兼容连接模式后,看起来就有些绕了:
<template> <!-- linkUrl 是从 mixinsLink 混入的属性 --> <a :href="linkUrl" @click.exact="handleClickLink($event, false)" @click.ctrl="handleClickLink($event, true)" @click.meta="handleClickLink($event, true)">...</a> <button ... @click="handleClickLink">...</button> </template> <script> ... export default { mixins: [ mixinsLink ], ... methods: { handleClickLink (event, new_window = false) { this.$emit('click', event); // handleCheckClick 是从 mixinsLink 混入进来的属性 this.handleCheckClick(event, new_window); } } ... }; </script>
handleClickLink
在 a
标签下被绑定了 3 次,分别带了 exact
、ctrl
、meta
修饰符,
用于模拟普通 a
标签的点击效果,可是为何不用 $event
对象的 ctrlKey
、metaKey
属性作判断呢?我仔仔细细看了 mixinsLink
的代码,惋惜仍是太过才疏学浅了,无法得出靠谱的结论,作了个简单 demo 对比各类实现的效果,也没看出个因此然。
另一个有问题的地方是 new_window
变量,其余变量名都是驼峰的,忽然来个下划线命名,有些突兀了。
最后提一点, type="ghost"
已通过期了,源码的 validator
函数也作了相应修改,如今传进 type="ghost"
会报错:
这错误信息,有点“硬”了?这里其实彻底能够多花些心思,报个 deprecated
警告,对升级者而言会更容易分辨出该作些什么修改。
附录: