Showing truncated text only on hover with Vue

落爺英雄遲暮 提交于 2019-12-04 04:55:22

问题


I tried it 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"
          @mouseover="showAll = true"
          @mouseout="showAll = false">
        {{getWord(club.description)}}
      </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 () {
    return {
      showAll: false,
      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);
        return c;
      }, []);
    }
  },
  methods: {
    getWord (desc) {
      if (this.showAll) return desc

      let value = desc;
      let length = 30;
      if (value.length <= length) {
        return value;
      } else {
        return value.substring(0, length) + '...';
      }
    }
  }
}
</script>

That almost works. But when I hover over the description in box 1, the description on all the other boxes also hover. It should only hover showing the truncated text on the box 1.

How can I solve this problem?


回答1:


The problem is that you have only one property to control the truncation of all items.

Firstly, you need to ensure that each club has its own boolean to control the text truncation. Lets use your already existing computed property to add a new reactive property for each club:

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); // Here we add the new reactive property.
    return c;
  }, []);
}

Secondly, let's use the <template> to handle visual things, keeping the right separation of concerns, using the new individual club.truncate property with a v-if/v-else block:

<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>

And now, the trucateText method only needs to care about returning the truncated text, since it's only called if we're truncating a description of one club:

methods: {
  trucateText (value) {
    const length = 30;
    return value.length <= length ?
      value : value.substring(0, length) + "...";
  }
}

Take a look at the fully working code here if any doubts persists.




回答2:


Try using key attribute for each item. If you set a mouseover for showAll, it will certainly display all the descriptions as it will return true for all. That's why, you should do dynamic list rendering here that Vue supports, similarly like this:

<div v-for="club in row" :key="club.id">

Also, I recommend you to have a look at the official documentation about dynamic list rendering :

https://vuejs.org/v2/guide/list.html




回答3:


You can create an array of boolean where each value corresponds to a team.

let formattedClubs= [{name: "team1", description: "desc team1"}, {name: "team2", description: "desc team2"}];
let showDescription = Array.from(formattedClubs, show => false);

You have the initial team array. You can create an array of the same size with values initialised to false.

In your template

<b-card-group deck deck v-for="(row, index) in formattedClubs">

Now you can match a team in the array formattedClubs[index] with a value in showDescription[index]

@mouseover="showDescription[index] = true" @mouseout="showDescription[index] = false"

Same in your events.



来源:https://stackoverflow.com/questions/52584451/showing-truncated-text-only-on-hover-with-vue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!