仅在Vue悬停时显示截断的文本

时间:2018-10-01 04:11:00

标签: css vue.js vuejs2 bootstrap-4 vue-component

我这样尝试过:

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

那几乎可行。但是,当我将鼠标悬停在框1的描述上时,所有其他框的描述也将悬停。它只应悬停在方框1上显示截断的文本。

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

问题是您只有一个属性来控制所有项目的截断。

首先,您需要确保每个俱乐部都有自己的布尔值来控制文本截断。让我们使用您已经存在的计算属性为每个俱乐部添加一个新的反应属性:

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;
  }, []);
}

第二,让我们使用<template>处理视觉事物,保持关注点正确分离,使用带有club.truncate / v-if块的新的单独v-else属性:

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

现在,trucateText方法只需要关心被截断的文本,因为只有在我们截断一个俱乐部的描述时才调用该文本:

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

如果仍有任何疑问,请查看fully working code here

答案 1 :(得分:0)

尝试为每个项目使用键属性。如果将鼠标悬停在showAll上,它肯定会显示所有描述,因为它将对所有返回true。这就是为什么,您应该在此处进行Vue支持的动态列表渲染,类似这样:

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

此外,我建议您查看有关动态列表呈现的官方文档:

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

答案 2 :(得分:0)

您可以创建一个布尔数组,每个值对应一个团队。

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

您拥有最初的团队阵容。您可以创建大小相同的数组,并将其值初始化为false。

在您的模板中

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

现在,您可以将数组formattedClubs[index]中的团队与showDescription[index]中的值匹配

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

与您的活动相同。