How can I showing truncated text only on hover wit

2019-09-20 08:31发布

问题:

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 :

If I hover the description, the result like this :

It change height of box list

How can I solve this problem?

I want the view like this :

回答1:

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.



回答2:

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.