iview 升级指南 —— Button 篇

iview 在今年 7 月 28 号发布了 3.0.0 版本,大版本升级每每意味着功能、接口的大变动。
虽然官网已经有长长的 更新日志,但看起来仍是有些抽象了,
因此我决定作个新旧版本的比较,盘点新版本到底为咱们带来了什么新特性。

这一篇给你们讲解的,是一个很经常使用的组件 —— Buttonjavascript

先看结论

新版 Button 有以下新特性:html

  1. 支持连接模式,可经过配置 to 属性启动
  2. 支持独立 ghost 属性,样式上可与其余的 type 值复合
  3. 支持自定义图标,可参考 《iview 3.x 升级盘点 —— Icon 篇》

Button 的升级相对仍是比较平滑的,须要注意两点:vue

  1. 新版本不支持 type="ghost",但可使用独立的 ghost 属性,因此升级前,建议全局搜索 type="ghost" 的调用
  2. 新旧版本的 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 属性值支持 stringobject 两种类型,iview 会优先使用 vue-router 的相关函数处理连接跳转;当应用环境中没有 vue-router 时,则会退化成普通的 window.location.href = this.to; 调用。
除了 toButton 还新增了 replacetarget 两个属性,用于补充连接的定义。replace 属性语义与 router-link 的 replace 属性的语义相同;target 属性则与 a 标签的 target 属性相同。github

总的来讲,在连接模式下,你能够把 Button 理解为一个阉割版的 router-link 组件。vue-router

独立 ghost 属性

幽灵按钮是一个曾经被普遍讨论的话题,如今已是一种很常规的设计了。这种设计指定按钮的背景色必须是透明的,而并无定义字体、边框样式,但旧版本 Button 只支持一种灰色调调的 ghost:api

新版本在这方面作了很大改进,将 ghost 样式独立为一类 class,配合其余 type 类型做为按钮字体、边框颜色的补充,相得益彰,能够看看 iview 官网提供的 示例antd

v2 ghost 各类形态按钮截图

多种色值形态的幽灵按钮确实能够大大提升提高实用性。曾经 1.x 版本 的 antd 也把 ghost 做为一种 type 看待,到了2.x 版本 也抽出来作为一个独立特性,iview 这个改进,看来也算是有依有据,亦步亦趋了。

不过,尴尬的是,iview 顺手把 default 的样式也给改了,对于设计有较高要求的团队得注意了:

default 按钮 v3 vs v2

问题

好了,特性与变动都聊完了,最后咱们来看看代码。 新版 Button 的代码只有 116 行却有很多值得玩味的地方:

1. 重复代码

新版 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,abutton 包裹的内容块完彻底全重复了, 彻底如出一辙诶。其实这一块代码能够抽成一个独立的组件,下降重复的。

另外, size 的定义,也挺尴尬的:

...
    export default {
        ...
        props: {
            ...
            size: {
                validator (value) {
                    return oneOf(value, ['small', 'large', 'default']);
                },
                default () {
                    return this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
                }
            }
            ...
        },
        ...
    };

从单个组件看,是没啥毛病,但居然能够在代码里找到 16 处彻底相同的代码,分别为:AutoCompleteAvatarButtonGroupCascaderCheckboxGroupCheckboxColorPickerPickerInputNumberInputRadioGroupRadioSelectSpinSwitchTable...这一块是能够抽成一个 mixin,这错误犯得有点低级了。

2. 事件处理

旧版本 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>

handleClickLinka 标签下被绑定了 3 次,分别带了 exactctrlmeta 修饰符,
用于模拟普通 a 标签的点击效果,可是为何不用 $event 对象的 ctrlKeymetaKey 属性作判断呢?我仔仔细细看了 mixinsLink 的代码,惋惜仍是太过才疏学浅了,无法得出靠谱的结论,作了个简单 demo 对比各类实现的效果,也没看出个因此然。

另一个有问题的地方是 new_window 变量,其余变量名都是驼峰的,忽然来个下划线命名,有些突兀了。

3. 过时的 ghost 值

最后提一点, type="ghost" 已通过期了,源码的 validator 函数也作了相应修改,如今传进 type="ghost" 会报错:

default 按钮 v3 vs v2

这错误信息,有点“硬”了?这里其实彻底能够多花些心思,报个 deprecated 警告,对升级者而言会更容易分辨出该作些什么修改。

附录:

  1. iview 升级指南 —— Icon 篇
  2. iview 升级指南 —— Button 篇
相关文章
相关标签/搜索