可重用的组件,用于在Vue.js中呈现按钮或路由器链接

时间:2017-11-29 00:28:12

标签: vue.js

我是使用Vue.js的新手,我在创建Button组件时遇到了困难。

如何将此组件编程为条件渲染?换句话说,也许应该将router-link呈现为button?像那样:

<Button type="button" @click="alert('hi!')">It's a button.</Button>
// -> Should return as a <button>.

<Button :to="{ name: 'SomeRoute' }">It's a link.</Button>
// -> Should return as a <router-link>.

5 个答案:

答案 0 :(得分:7)

您可以在render()内切换代码,也可以只使用<component>

根据official specification for Dynamic Components

  

您可以使用相同的挂载点,并使用保留的<component>元素在多个组件之间动态切换,并动态绑定到它的is属性。

以下是您案例的示例:

<强> ButtonControl.vue

<template>
  <component :is="type" :to="to">
    {{ value }}
  </component>
</template>

<script>
export default {
  computed: {
    type () {
      if (this.to) {
        return 'router-link'
      }

      return 'button'
    }
  },

  props: {
    to: {
      required: false
    },
    value: {
      type: String
    }
  }
}
</script>

现在您可以轻松地将其用于button

<button-control value="Something"></button-control>

router-link

<button-control to="/" value="Something"></button-control>

在创建可能包含链接或不具有链接的元素(例如按钮或卡片)时,请记住这是一个很好的行为。

答案 1 :(得分:3)

您可以通过render functions实现这一目标。

render: function (h) {
if(this.to){ // i am not sure if presence of to props is your condition
  return h(routerLink, { props: { to: this.to } },this.$slots.default)
}
return h('a', this.$slots.default)
}

这应该可以帮助你开始正确的方向

答案 2 :(得分:3)

您可以使用v-ifv-else-ifv-else指令创建可以动态呈现为不同标记的自定义组件。只要Vue可以告诉自定义组件在渲染后将具有单个根元素,它就不会抱怨。

但首先,您不应该使用&#34;内置或保留的HTML元素&#34;来命名自定义组件,因为您将获得的Vue警告会告诉您。

对我来说,为什么你希望单个组件有条件地呈现为<button><router-link>(它本身默认呈现为<a>元素,这对我没有意义。 )。但如果你真的想这样做,这就是一个例子:

&#13;
&#13;
Vue.use(VueRouter);

const router = new VueRouter({
  routes: [ { path: '/' } ]
})

Vue.component('linkOrButton', {
  template: `
    <router-link v-if="type === 'link'" :to="to">I'm a router-link</router-link>
    <button v-else-if="type ==='button'">I'm a button</button>
    <div v-else>I'm a just a div</div>
  `,
  props: ['type', 'to']
})

new Vue({ el: '#app', router })
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
  <link-or-button type="link" to="/"></link-or-button>
  <link-or-button type="button"></link-or-button>
  <link-or-button></link-or-button>
</div>
&#13;
&#13;
&#13;

如果您只是尝试将<router-link>呈现为<button>而不是<a>,那么您可以通过tag道具来指定<router-link>本身:

&#13;
&#13;
Vue.use(VueRouter);

const router = new VueRouter({
  routes: [ { path: '/' } ]
})

new Vue({ el: '#app', router })
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
  <router-link to="/">I'm an a</router-link>
  <router-link to="/" tag="button">I'm a button</router-link>
</div>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

我认为您无法在没有父元素的情况下有条件地呈现<router-link><button>

您可以做的是决定在点击上做什么,以及根据传递的道具为您的元素设置样式。

template: `<a :class="{btn: !isLink, link: isLink}" @click="handleClick"><slot>Default content</slot></a>`,
props: ['to'],
computed: {
  isLink () { return !!this.to }
},
methods: {
  handleClick () {
    if (this.isLink) {
      this.$router.push(this.to)
    }
    this.$emit('click') // edited this to always emit
  }
}

答案 4 :(得分:1)

我会遵循@Phil的建议并使用v-if,但如果您更喜欢使用一个组件,则可以在点击方式中programmatically navigate

您的代码可能如下所示:

<template>
  <Button type="button" @click="handleLink">It's a button.</Button>
</template>
<script>
  export default {
    name: 'my-button',
    props: {
      routerLink: {
        type: Boolean,
        default: false
      }
    },
    methods: {
      handleLink () {
        if (this.routerLink) {
          this.$router.push({ name: 'SomeRoute' })
        } else {
          alert("hi!")
        }
      }
    }
  }
</script>