Commit a25314e846ea4fc00848bc66a85b5a240ac9ce29

Authored by Aresn
Committed by GitHub
2 parents 1c35a44d d77476f8

Merge pull request #4228 from VanMess/better-button

Better button
src/components/button/button.vue
1 <template> 1 <template>
2 - <a  
3 - v-if="to"  
4 - :class="classes"  
5 - :disabled="disabled"  
6 - :href="linkUrl"  
7 - :target="target"  
8 - @click.exact="handleClickLink($event, false)"  
9 - @click.ctrl="handleClickLink($event, true)"  
10 - @click.meta="handleClickLink($event, true)"> 2 + <component :is="tagName" :class="classes" :disabled="disabled" @click="handleClickLink" v-bind="tagProps">
11 <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon> 3 <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon>
12 <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon> 4 <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon>
13 <span v-if="showSlot" ref="slot"><slot></slot></span> 5 <span v-if="showSlot" ref="slot"><slot></slot></span>
14 - </a>  
15 - <button  
16 - v-else  
17 - :type="htmlType"  
18 - :class="classes"  
19 - :disabled="disabled"  
20 - @click="handleClickLink">  
21 - <Icon class="ivu-load-loop" type="ios-loading" v-if="loading"></Icon>  
22 - <Icon :type="icon" :custom="customIcon" v-if="(icon || customIcon) && !loading"></Icon>  
23 - <span v-if="showSlot" ref="slot"><slot></slot></span>  
24 - </button> 6 + </component>
25 </template> 7 </template>
26 <script> 8 <script>
27 import Icon from '../icon'; 9 import Icon from '../icon';
@@ -98,14 +80,34 @@ @@ -98,14 +80,34 @@
98 [`${prefixCls}-ghost`]: this.ghost 80 [`${prefixCls}-ghost`]: this.ghost
99 } 81 }
100 ]; 82 ];
  83 + },
  84 + // Point out if it should render as <a> tag
  85 + isHrefPattern() {
  86 + const {to} = this;
  87 + return !!to;
  88 + },
  89 + tagName() {
  90 + const {isHrefPattern} = this;
  91 + return isHrefPattern ? 'a' : 'button';
  92 + },
  93 + tagProps() {
  94 + const {isHrefPattern} = this;
  95 + if(isHrefPattern) {
  96 + const {linkUrl,target}=this;
  97 + return {href: linkUrl, target};
  98 + } else {
  99 + const {htmlType} = this;
  100 + return {type: htmlType};
  101 + }
101 } 102 }
102 }, 103 },
103 methods: { 104 methods: {
104 // Ctrl or CMD and click, open in new window when use `to` 105 // Ctrl or CMD and click, open in new window when use `to`
105 - handleClickLink (event, new_window = false) { 106 + handleClickLink (event) {
106 this.$emit('click', event); 107 this.$emit('click', event);
  108 + const openInNewWindow = event.ctrlKey || event.metaKey;
107 109
108 - this.handleCheckClick(event, new_window); 110 + this.handleCheckClick(event, openInNewWindow);
109 } 111 }
110 }, 112 },
111 mounted () { 113 mounted () {
test/unit/specs/button.spec.js 0 → 100644
  1 +import { createVue, destroyVM } from '../util';
  2 +
  3 +describe('Button.vue', () => {
  4 + let vm;
  5 + afterEach(() => {
  6 + destroyVM(vm);
  7 + });
  8 +
  9 + it('should render as <a>', done => {
  10 + vm = createVue(`
  11 + <Button to="http://www.thinkinfe.tech/">Think in FE</Button>
  12 + `);
  13 + expect(vm.$el.tagName).to.equal('A');
  14 + done();
  15 + });
  16 +
  17 + it('should render as <button>', done => {
  18 + vm = createVue(`
  19 + <Button>Think in FE</Button>
  20 + `);
  21 + expect(vm.$el.tagName).to.equal('BUTTON');
  22 + done();
  23 + });
  24 +
  25 + it('handle with `type` attribute', done => {
  26 + // should render with `type` attribute
  27 + // if it is a <button>
  28 + vm = createVue(`
  29 + <Button htmlType="reset">Think in FE</Button>
  30 + `);
  31 + expect(vm.$el.getAttribute('type')).to.equal('reset');
  32 +
  33 + // should't render with `type` attribute
  34 + // if it is a <button>
  35 + vm = createVue(`
  36 + <Button to="http://www.thinkinfe.tech/" htmlType="reset">Think in FE</Button>
  37 + `);
  38 + expect(vm.$el.getAttribute('type')).to.equal(null);
  39 + done();
  40 + });
  41 +
  42 + it('should change loading state', done => {
  43 + vm = createVue({
  44 + template: `
  45 + <Button :loading="loading" @click="fetch">Think in FE</Button>
  46 + `,
  47 + data() {
  48 + return {loading: false};
  49 + },
  50 + methods: {
  51 + fetch() {
  52 + this.loading = true;
  53 + }
  54 + }
  55 + });
  56 + vm.$el.click();
  57 + vm.$nextTick(() => {
  58 + expect(vm.$el.classList.contains('ivu-btn-loading')).to.equal(true);
  59 + const $icons = vm.$el.querySelectorAll('.ivu-icon');
  60 + expect($icons.length).to.equal(1);
  61 + expect($icons[0].classList.contains('ivu-load-loop')).to.equal(true);
  62 + expect($icons[0].classList.contains('ivu-icon-ios-loading')).to.equal(true);
  63 + done();
  64 + });
  65 + });
  66 +});