How can I showing truncated text only on hover wit

2019-09-20 09:00发布

My script of vue component like this :

<template>
  ...
    <b-card-group deck v-for="row in formattedClubs">
        <b-card  v-for="club in row"
                img-src="http://placehold.it/130?text=No-image"
                img-alt="Img"
                img-top>
            <h4 class="card-title" 
                @mouseenter="club.truncate = false"
                @mouseleave="club.truncate = true">
                <template v-if="club.truncate">{{trucateText(club.description)}}</template>
                <template v-else>{{club.description}}</template>
            </h4>
            <p class="card-text">
                {{club.price}}
            </p>
            <p class="card-text">
                {{club.country}}
            </p>
            <div slot="footer">
                <b-btn variant="primary" block>Add</b-btn>
            </div>
        </b-card>
    </b-card-group>
  ...
</template>

<script>
export default {
  data: function () {
    return {
      clubs: [
          {id:1, description:'chelsea is the best club in the world and chelsea has a great player', price:1000, country:'england'},
          {id:2, description:'liverpool has salah', price:900, country:'england'},
          {id:3, description:'mu fans', price:800, country:'england'},
          {id:4, description:'city has a great coach. Thas is guardiola', price:700, country:'england'},
          {id:5, description:'arsenal player', price:600, country:'england'},
          {id:6, description:'tottenham in london', price:500, country:'england'},
          {id:7, description:'juventus stadium', price:400, country:'italy'},
          {id:8, description:'madrid sell ronaldo', price:300, country:'spain'},
          {id:9, description:'barcelona in the spain', price:200, country:'spain'},
          {id:10, description:'psg buys neymar at a fantastic price', price:100, country:'france'}
      ]
    }
  },
  computed: {
      formattedClubs() {
          return this.clubs.reduce((c, n, i) => {
              if (i % 4 === 0) c.push([]);
              c[c.length - 1].push(n);
              this.$set(n, 'truncate', true); 
              return c;
          }, []);
      }
  },
  methods: {
      trucateText (value) {
          const length = 30;
          return value.length <= length ? value : value.substring(0, length) + "...";
      }
  }
}
</script>

If the script executed, the view like this :

enter image description here

If I hover the description, the result like this :

enter image description here

It change height of box list

How can I solve this problem?

I want the view like this :

enter image description here

2条回答
唯我独甜
2楼-- · 2019-09-20 09:32

We can see that you're using bootstrap-vue. Nice, so you can use v-b-tooltip directive and let itself control the hover behavior. As you don't need to track it by yourself anymore for each club, you can remove that reative property from your computed property formattedClubs:

this.$set(n, 'truncate', true); // Remove this line.

Now, update your template to use the directive only if the truncation is needed:

<h4 class="card-title"
    v-if="club.description.length > 30"
    v-b-tooltip.hover.bottom
    :title="club.description">
  {{trucate(club.description)}}
</h4>
<h4 v-else>{{club.description}}</h4>

And, of course, you can now style it the way you want overriding the right Boostrap styles:

.tooltip.show {
  opacity: 1;
} 

.tooltip-inner {
  background: #fff;
  color: #000;
  padding: .5em 1em;
  border: 1px solid #bbb;
  box-shadow: 0 3px 8px rgba(0, 0, 0, .15);
}

.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow, .tooltip.bs-tooltip-bottom .arrow {
    position: relative;
    background: #fff;
  top: 1px;
  width: 16px;
}

.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::before, .tooltip.bs-tooltip-bottom .arrow::before, .tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::after, .tooltip.bs-tooltip-bottom .arrow::after {
  bottom: 0;
    left: 50%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}

.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::after, .tooltip.bs-tooltip-bottom .arrow::after {
  border-color: rgba(255, 255, 255, 0);
    border-bottom-color: #fff;
    border-width: 8px;
    margin-left: -8px;
}

.tooltip.bs-tooltip-auto[x-placement^=bottom] .arrow::before, .tooltip.bs-tooltip-bottom .arrow::before {
  border-color: rgba(187, 187, 187, 0);
    border-bottom-color: #bbb;
    border-width: 9px;
    margin-left: -9px;
}

Take a look at the fully working sampe here if you want.

查看更多
等我变得足够好
3楼-- · 2019-09-20 09:32

I would simply wrap your truncated text with a tooltip component. You can pass the full text into this component as a prop.

On hover you can show the tooltip by using @mouseover and remove it by using @mouseleave.

The tooltip itself can be a position absolute element with a max-width. I am not going to type all of this out, but this should get you started.

查看更多
登录 后发表回答