我的 Vue 应用程序遇到问题:当我单击某个产品时,会触发 navigationAndChange 函数,该函数会获取该产品的 ID 并将我带到包含该产品的页面。此页面上的某些元素包含该产品的图片,最后一个元素应该有一个“active”类,允许它有一个边框,这意味着最后一个图像显示在屏幕上。问题是,在实现 NavigationAndChange 函数时,imgBlocks 变量存储一个数组,其中的元素包含旧产品图像的值,当转换到具有另一个产品的页面时,我需要它更改此值,所以新产品图像的最后一个元素已采用“活跃”类别。怎么做?我提供下面的代码。
<script setup>
import { computed, ref, onMounted, nextTick } from "vue";
import { useProductStore } from "../stores/store.js";
import { useRouter, RouterLink } from "vue-router";
import btn from "./btn.vue";
import orderBtn from "./orderBtn.vue";
const router = useRouter();
const productStore = useProductStore();
let product = computed(() => productStore.getProduct);
const extraProducts = computed(() => productStore.getExtraProducts);
// change image
let activeImg = ref('');
activeImg.value = product?.value?.thumbnail;
let imgBlocks = ref([]);
onMounted(() => {
imgBlocks.value = document.querySelectorAll('.img-good');
let lastNum = imgBlocks.value.length - 1;
let lastBlock = imgBlocks.value[lastNum];
lastBlock.classList.add('active')
})
function changeImg(event, img) {
activeImg.value = img;
const imgBlock = event.target.closest('.img-good');
if (imgBlock.classList.contains('active')) {
imgBlock.classList.remove('active');
} else {
imgBlock.classList.add('active');
}
for (let i = 0; i < imgBlocks.value.length; i++) {
if (imgBlocks.value[i] != imgBlock) {
imgBlocks.value[i].classList.remove('active')
}
}
}
// change product
function changeProduct(extraProduct) {
productStore.id = extraProduct.id;
localStorage.setItem("productStore", JSON.stringify(productStore));
activeImg.value = extraProduct.thumbnail;
// location.reload()
// console.log(imgBlocks.value);
let images = document.querySelectorAll('.img-good');
imgBlocks.value = images;
console.log(imgBlocks.value);
}
function navigateAndChange(extraProduct) {
// Execute the router navigation first
router.push(`/productCard/${extraProduct.id}`);
// Execute the changeProduct function after a delay
setTimeout(() => {
changeProduct(extraProduct);
}, 100);
}
</script>
<template>
<div>
<section class="container products">
<div class="products__info">
<div class="products__info-img">
<div class="img-gallery" ref="imgGallery">
<div class="img-good" v-for="image in product.images" @click="changeImg($event,
image)" ref="imgBlocks">
<img :src="image" alt="">
</div>
</div>
<img :src="activeImg" alt="" class="main-img" />
</div>
<div class="products__info-description">
<h3>{{ product.title }}</h3>
<p>$ {{ product.price }}</p>
<h4>Product description</h4>
<p class="description">{{ product.description }}</p>
<div class="products-order">
<div class="order-btns">
<orderBtn text="-" @click="decrease(product)"></orderBtn>
<div class="ordered-quantity">
{{ product.amount > 0 ? product.amount : 0 }}
</div>
<orderBtn text="+" @click="increase(product)"></orderBtn>
</div>
<RouterLink :to="`/shoppingCart`">
<btn text="Buy NOW"></btn>
</RouterLink>
<div class="icon-like" @click="likeProduct($event, product)" :class="{ active: product.liked == true }"></div>
</div>
</div>
</div>
<div class="products__extra">
<h2>You may be interested in</h2>
<div class="products__extra-content">
<div class="extra__item" v-for="extraProduct in extraProducts" :key="extraProduct.id">
<div class="extra__item-img">
<RouterLink :to="`/productCard/${extraProduct.id}`" @click="
navigateAndChange(extraProduct)"></RouterLink>
<img :src="extraProduct.thumbnail" alt="" />
<div class="icons">
<div class="icon-cart" @click="addOrDeleteProduct(extraProduct)" :class="{ active: extraProduct.amount }">
</div>
<div class="icon-like" @click="likeProduct($event, extraProduct)"
:class="{ active: extraProduct.liked == true }"></div>
</div>
<h5>{{ Math.ceil(extraProduct.discountPercentage) }} % OFF</h5>
</div>
<div class="extra__item-description">
<h4>{{ extraProduct.title }}</h4>
<p>$ {{ extraProduct.price }}</p>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
这里有很多“不太好”的代码。抱歉发了这么长的帖子。不过,我想解决您的代码的两个主要方面。更新产品信息,然后更新图像上的 active
类。公平警告,并非所有下面的代码对于您的实际应用程序来说实际上都是“正确的”,并且可能需要一定量的重构才能 100% 工作。请更多地将其视为示例代码。
changeProduct
函数调用并不是一个好习惯。这非常hacky。
鉴于这就是你推动的方式router.push(`/productCard/${extraProduct.id}`);
我假设你有一个像这样定义的路线
{ path: '/productCard/:id', component: productComponent, props: true }
如果您没有
props: true
,您应该添加它。这样,
:id
参数将自动分配为组件中的 prop。https://router.vuejs.org/guide/essentials/passing-props.html当props
设置为
时,true
将被设置为组件道具。 现在,如果您在组件上定义一个 proproute.params
id
,它将从路由 URL 接收
/:id
参数const props = defineProps({
id: {
type: String, // URL param is always type String. You can cast to Number later if needed
default: '1'
}
})
现在观看
此道具并调用更新商店和页面上的产品信息所需的所有其他功能。
watch(
() => props.id,
newId => {
setNewProduct(newId) // updates store, product object, images array, etc.
}
)
更新图像
active
imgBlocks
变量存在误解。在这里查看相关的div:
<div class="img-good" v-for="image in product.images" @click="changeImg($event,
image)" ref="imgBlocks">
添加
ref="imgBlocks"
很好,但您没有在脚本代码中正确使用它。这称为“模板引用”。安装时,脚本代码中的
imgBlocks
将自动分配该 div 的物理 DOM 元素。这意味着像这样的代码imgBlocks.value = document.querySelectorAll('.img-good');
是不必要的,可以删除(document
接口几乎应该从不与Vue一起使用)。实际上,我什至根本不会使用
imgBlocks
之类的东西。使用类绑定我们可以避免手动添加/删除类的麻烦,而是根据图像本身设置条件。
获取product
信息后,将 Product.images 数组映射为图像 objects数组,其中一个属性称为
isActive
最初设置为 false,(如果您希望它已经处于活动状态,则第一个属性除外默认情况下)。那么也许你最终会得到一个看起来像这样的图像数组:
product.images = [
{
id: 0,
src: '/foo.jpg',
isActive: true
},
{
id: 1,
src: '/bar.jpg',
isActive: false
},
{
id: 2,
src: '/baz.jpg',
isActive: false
}
]
现在更新模板代码以包含以下类绑定...
<!-- always include a unique key with v-for -->
<div
v-for="image in product.images"
:key="image.id"
@click="changeImg(image)"
>
<img :src="image.src" alt="" :class="{ active: image.isActive }">
</div>
仅当
active
为 true 时,才会分配类别
image.isActive
。因此,当单击图像时,
changeImg
函数应为刚刚单击的图像设置 isActive = true
,而对其他图像设置为 false。function changeImg(image) {
product.value.images.forEach(
i => (i.isActive = i.id === image.id ? true : false)
)
}
现在无论单击哪个图像都将处于活动状态。更改产品时,请始终将 products.images
重新映射为对象数组,并使用
isActive
属性设置您想要的初始渲染方式。
codesandbox.io 示例如果有帮助的话,我制作了一个 codesandbox