如何仅在 vue.js 中对特定点击的卡片应用切换/样式?

Posted

技术标签:

【中文标题】如何仅在 vue.js 中对特定点击的卡片应用切换/样式?【英文标题】:How to apply toggling / styles on a particular clicked card only in vue.js? 【发布时间】:2021-09-20 19:08:46 【问题描述】:

我开发了一个页面 DisplayBooks.vue,它负责显示来自后端 API 的响应的书籍,基于它将显示在我的 UI 页面中的数据,在我的 UI 页面中,每张卡片都包含两个按钮(添加到袋子和添加TO BAG)当用户点击任何卡片添加到袋子按钮时,它会隐藏添加到袋子并仅在特定点击的卡片上显示添加到袋子按钮,请帮助我实现这个目标。

DisplayBooks.vue

<template>
<div class="carddisplay-section">
    <div v-for="book in books" :key="book.id" class="card book">
        <div class="image-section">
            <div class="image-container">
                <img  v-bind:src="book.file" />
            </div>
        </div>
        <div class="title-section">
            book.name
        </div>
        <div class="author-section">
            by book.author
        </div>
        <div class="price-section">
            Rs. book.price<label class="default">(2000)</label>
            <button v-if="flag" class="btn-grp" type="submit" @click="handlesubmit();Togglebtn();">close</button>
        </div>
        <div class="buttons">
            <div class="button-groups">
                <button type="button"  class="AddBag">Add to Bag</button>
                
            </div>
            <div  class="AddedBag">
                <button class="big-btn">Added to Bag</button>
            </div>
        </div>
    </div>

</div>
</template>

<script>
import service from '../service/User'

export default 
    data() 
        return 
           
            flag: true,
            state: true,
            clickedCard: '',
            books: [
                id: 0,
                file: 'https://images-na.ssl-images-amazon.com/images/I/41MdP5Tn0wL._SX258_BO1,204,203,200_.jpg',
                name: 'Dont Make me think',
                author: 'Sai',
                price: '1500'
            , ]
        
    ,
    methods: 
       
        
        flip() 
            this.state = !this.state;
        ,
        Togglebtn() 
            this.flag = !this.flag;
        ,
        handlesubmit() 
            service.userDisplayBooks().then(response => 
                this.books.push(...response.data);     
            )
        ,
    

</script>

<style lang="scss" scoped>
    @import "@/styles/DisplayBooks.scss";
</style>

DisplayBooks.scss

@import "colors";
.carddisplay-section 
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    align-content: space-around;
    gap: 10px;

.card:hover
    box-shadow:0.6px 0.6px 0.6px 0.6px rgb(173, 206, 206);

.card 
    margin-top: 55px;
    margin-left: 110px;
    background:$pink;
    // width: 235px;
    // height: 275px;
    width: 235px;
height: 315px;
    background: $pale_white 0% 0% no-repeat padding-box;
    border: 1px solid $border_clr;
    border-radius: 3px;
    opacity: 1;


.image-section 
    width: 233px;
    height: 172px;
    background: #F5F5F5 0% 0% no-repeat padding-box;
    border-radius: 2px 2px 0px 0px;
    opacity: 1;


img
    margin-left: 67px;
    margin-top: 17px;
    width: 105px;
    height: 135px;
    opacity: 1;
    border:none;


.title-section 
    text-align: left;
    font: normal normal normal 14px/19px Roboto;
    letter-spacing: 0.2px;
    color: $light_black;
    opacity: 1;
    margin-left: 20px;
    margin-top: 3px;
    width: 130px;
    height: 19px;
    text-transform: capitalize;


.author-section 
    text-align: left;
    font: normal normal normal 13px/13px Roboto;
    letter-spacing: 0px;
    color: $light_grey;
    opacity: 1;
    width: 123px;
    height: 13px;
    margin-left: 20px;
    margin-top: 7px;


.price-section 
    text-align: left;
    font: normal normal bold 12px/16px Roboto;
    letter-spacing: 0px;
    color: $light_black;
    opacity: 1;
    margin-left: 20px;
    height: 16px;
    margin-top: 26px;
    display: flex;
    justify-content: flex-start;



label 
    text-decoration-line: line-through;
    font: normal normal normal 10px/13px Roboto;
    letter-spacing: 0px;
    color: $light_grey;
    opacity: 1;
    width: 36px;
    height: 13px;
    margin-top: 2.5px;
    margin-left: 1em;


button[type="submit"] 
    border: none;
    padding-left: 65px;
    background: none;
    font-size: 15;

.button-groups
    display:flex;
    margin-top:8px;

.AddBag
    background: #A03037 0% 0% no-repeat padding-box;
    border-radius: 2px;
    opacity: 1;
    width: 93px;
    height: 29px;
    margin-left:20px;
    color: #FFFFFF;
    text-transform: uppercase;
    opacity: 1;
    font-size: small;

.wishlist
    margin-left:4px;
    color: #FFFFFF;
    text-transform: uppercase;
    opacity: 1;
    font-size: small;
    border: 1px solid #7c7a7a;
    border-radius: 2px;
    opacity: 1;
    color: #0A0102;
    width:93px;

.big-btn
    width: 191px;
height: 29px;
margin-left:20px;
background: #3371B5 0% 0% no-repeat padding-box;
border-radius: 2px;
opacity: 1;
color:#FFFFFF;

   

【问题讨论】:

【参考方案1】:

添加另一个数组,其中包含通过单击按钮添加到 BAG 添加的书籍 ID,然后使用 v-if/v-else 进行条件渲染:

    data() 
        return 
           
            flag: true,
            state: true,
            clickedCard: '',
            addedBooks:[],
            books: [....]
        
    ,

在模板中:

    <div class="buttons">
            <div class="button-groups" v-if="!addedBooks.includes(book.id)">
                <button type="button"  @click="addedBooks.push(book.id)"  class="AddBag">Add to Bag</button>
                
            </div>
            <div  class="AddedBag" v-else>
                <button class="big-btn" @click="addedBooks=addedBooks.filter(id=>id!==book.id)">Added to Bag</button>
            </div>
        </div>

示例

new Vue(
  el: "#app",

  data() 
    return 

      flag: true,
      state: true,
      clickedCard: '',
      addedBooks: [],
      books: [
          id: 0,
          file: 'https://images-na.ssl-images-amazon.com/images/I/41MdP5Tn0wL._SX258_BO1,204,203,200_.jpg',
          name: 'Dont Make me think',
          author: 'Sai',
          price: '1500'
        ,
        
          id: 1,
          file: 'https://images-na.ssl-images-amazon.com/images/I/41MdP5Tn0wL._SX258_BO1,204,203,200_.jpg',
          name: 'Dont Make me think',
          author: 'Sai',
          price: '1500'
        ,

      ]
    
  ,
  methods: 


    flip() 
      this.state = !this.state;
    ,
    Togglebtn() 
      this.flag = !this.flag;
    ,

  
)
.carddisplay-section 
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  align-content: space-around;
  gap: 10px;


.card:hover 
  box-shadow: 0.6px 0.6px 0.6px 0.6px rgb(173, 206, 206);


.card 
  margin-top: 55px;
  margin-left: 110px;
  background: $pink;
  // width: 235px;
  // height: 275px;
  width: 235px;
  height: 315px;
  background: $pale_white 0% 0% no-repeat padding-box;
  border: 1px solid $border_clr;
  border-radius: 3px;
  opacity: 1;


.image-section 
  width: 233px;
  height: 172px;
  background: #F5F5F5 0% 0% no-repeat padding-box;
  border-radius: 2px 2px 0px 0px;
  opacity: 1;


img 
  margin-left: 67px;
  margin-top: 17px;
  width: 105px;
  height: 135px;
  opacity: 1;
  border: none;


.title-section 
  text-align: left;
  font: normal normal normal 14px/19px Roboto;
  letter-spacing: 0.2px;
  color: $light_black;
  opacity: 1;
  margin-left: 20px;
  margin-top: 3px;
  width: 130px;
  height: 19px;
  text-transform: capitalize;


.author-section 
  text-align: left;
  font: normal normal normal 13px/13px Roboto;
  letter-spacing: 0px;
  color: $light_grey;
  opacity: 1;
  width: 123px;
  height: 13px;
  margin-left: 20px;
  margin-top: 7px;


.price-section 
  text-align: left;
  font: normal normal bold 12px/16px Roboto;
  letter-spacing: 0px;
  color: $light_black;
  opacity: 1;
  margin-left: 20px;
  height: 16px;
  margin-top: 26px;
  display: flex;
  justify-content: flex-start;


label 
  text-decoration-line: line-through;
  font: normal normal normal 10px/13px Roboto;
  letter-spacing: 0px;
  color: $light_grey;
  opacity: 1;
  width: 36px;
  height: 13px;
  margin-top: 2.5px;
  margin-left: 1em;


button[type="submit"] 
  border: none;
  padding-left: 65px;
  background: none;
  font-size: 15;


.button-groups 
  display: flex;
  margin-top: 8px;


.AddBag 
  background: #A03037 0% 0% no-repeat padding-box;
  border-radius: 2px;
  opacity: 1;
  width: 93px;
  height: 29px;
  margin-left: 20px;
  color: #FFFFFF;
  text-transform: uppercase;
  opacity: 1;
  font-size: small;


.wishlist 
  margin-left: 4px;
  color: #FFFFFF;
  text-transform: uppercase;
  opacity: 1;
  font-size: small;
  border: 1px solid #7c7a7a;
  border-radius: 2px;
  opacity: 1;
  color: #0A0102;
  width: 93px;


.big-btn 
  width: 191px;
  height: 29px;
  margin-left: 20px;
  background: #3371B5 0% 0% no-repeat padding-box;
  border-radius: 2px;
  opacity: 1;
  color: #FFFFFF;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div class="carddisplay-section">
    <div v-for="book in books" :key="book.id" class="card book">
      <div class="image-section">
        <div class="image-container">
          <img v-bind:src="book.file" />
        </div>
      </div>
      <div class="title-section">
        book.name
      </div>
      <div class="author-section">
        by book.author
      </div>
      <div class="price-section">
        Rs. book.price<label class="default">(2000)</label>
        <button v-if="flag" class="btn-grp" type="submit" @click="">close</button>
      </div>
      <div class="buttons">
        <div class="button-groups" v-if="!addedBooks.includes(book.id)">
          <button type="button" @click="addedBooks.push(book.id)" class="AddBag">Add to Bag</button>

        </div>
        <div class="AddedBag" v-else>
          <button class="big-btn" @click="addedBooks=addedBooks.filter(id=>id!==book.id)">Added to Bag</button>
        </div>
      </div>
    </div>

  </div>
</div>

【讨论】:

点击添加到袋子按钮它应该隐藏并显示添加到袋子功能不起作用 请澄清更多 当用户点击添加到袋子按钮时,它隐藏添加到袋子按钮并显示添加到袋子按钮直到它工作,只有当用户再次点击添加到袋子按钮时才会这样它应该返回到 ADD TO BAG 按钮(意味着 ADDED TO BAG 按钮应该被隐藏) addedBooks 填充了添加的ID? 试用&lt;button class="big-btn" @click="addedBooks=addedBooks.filter(id=&gt;id!==book.id)"&gt;Added to Bag&lt;/button&gt;

以上是关于如何仅在 vue.js 中对特定点击的卡片应用切换/样式?的主要内容,如果未能解决你的问题,请参考以下文章

如何将点击的卡片按钮 id 传递给 vue.js 中的后端 URL 路径?

如何将点击卡片的 id 和卡片内容传递给 vue.js 中的另一个组件?

Vue.js - 切换特定问题答案的方法

如何使用 Vue.js 切换按钮?

颤振状态不会更新

如何在 vue 上使用 eventBus 触发点击事件?