Nuxt/Vue @Click值仅触发一次

jc3wubiy  于 2023-03-31  发布在  Vue.js
关注(0)|答案(1)|浏览(210)

我有一个名为'ProductGrid.Vue'和'LoadItem.vue'的组件(这是侧加载器菜单)。
目前,我在两个地方都有名为show的Prop,一旦LoadItem菜单关闭,我就不能再次触发show = true。
这可以在Here上进行测试

ProductGrid.Vue

<template>
<LoadItem  v-if="show" :show="show" />
  <section class="py-12 sm:py-16 lg:py-6 bg-gray-50">
    <div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
      <div class="flex items-center justify-center lg:justify-between">
        <!--Filters will go here-->
      </div>
      <div
        class="
          grid grid-cols-2
          gap-5
          mt-0
          sm:grid-cols-2
          md:grid-cols-3
          lg:grid-cols-5
          sm:mt-10
        "
      >
        <div
          class="
            relative
            overflow-hidden
            bg-white
            border border-gray-200
            rounded-xl
            group
          "
          v-for="ProductData in data"
        >
          <div class="absolute z-10 top-3 right-3">
            <button
              type="button"
              class="
                inline-flex
                items-center
                justify-center
              "
            >
            </button>
          </div>
          <div class="relative">
            <div class="aspect-w-1 aspect-h-1">
              <img
                class="object-cover w-full h-full"
                :src="ProductData.Image"
                alt=""
              />
            </div>
            <div class="px-4 py-4">
             <!--Store Name-->
            {{(storeCount = ProductData.store_info.length, null)}}
            <div class="mt-0.5 text-xs sm:text-sm text-gray-400">
            <template v-if="ProductData.store_info.length <= 2">
               <template v-for="(item, key, index) in ProductData.store_info.slice(0,2)">
                {{item.store_name}}<span v-if="key+1 < storeCount">, </span>
              </template>
              <span v-if="storeCount > 2">+ {{storeCount-2}} More</span>
            </template>
            </div>
            <!--End Store Name-->
              <h3 class="text-sm font-medium text-gray-800">
                <NuxtLink :to="`/product/${ProductData.id}`" title="">
                  {{ ProductData.product_name }}
                  <span class="absolute inset-0" aria-hidden="true"></span>
                </NuxtLink>
              </h3>
              <div class="flex items-center">
                <div class="flex items-center space-x-px">
                  <!--Ratings-->
                  <!--<star-rating
                    v-model:rating="ProductData.current_rating"
                    :round-start-rating="false"
                    :star-size="14"
                    :show-rating="false"
                  ></star-rating>-->
                  <div class="rating-holder">
                    <div
                      class="c-rating c-rating--small"
                      :data-rating-value="
                        Math.round(ProductData.current_rating / 0.25) * 0.25
                      "
                    >
                      <button>1</button>
                      <button>2</button>
                      <button>3</button>
                      <button>4</button>
                      <button>5</button>
                    </div>
                  </div>
                  <div class="text-xs text-gray-400">
                    ({{ ProductData.current_rating }})
                  </div>
                </div>
              </div>
              <p class="mt-0.5 text-xs sm:text-sm font-medium text-gray-400">
                {{ ProductData.current_reviews }} Reviews
              </p>
              <p class="mt-2 text-sm font-bold text-gray-900 flex">
                {{
                  Number(ProductData.current_price).toLocaleString('en-US', {
                    style: 'currency',
                    currency: 'USD',
                  })
                }}
                <!--Analytics Stats Start-->
                <div v-if="ProductData.previous_price_day > 0.00">
                  <div v-if="ProductData.current_price == ProductData.previous_price_day">
                    <!--Price is the same-->
                 </div>
                  <div v-else="ProductData.current_price > ProductData.previous_price_day">
                   <!--Price has increased-->
                   
                 </div>
                  <div v-else="ProductData.current_price < ProductData.previous_price_day">
                    <!--Price has decreased-->
                    <img class="
                    w-2.5
                    "
                    style="
                    margin-left:2.2px;
                    padding-top:40%;
                    "
                    src="https://upload.wikimedia.org/wikipedia/commons/8/82/Decrease.svg">
                 </div>
                </div>
                <div v-else>
                    <!--Price is the same-->
                </div>
                <!--Stats End-->
              </p>
            </div>
          </div>
          <div
            class="
              absolute
              inset-x-0
              bottom-0
              transition-all
              duration-200
              translate-y-full
              group-hover:translate-y-0
            "
          >
            <span title="">
              <button
                type="button"
                class="
                  flex
                  items-center
                  justify-center
                  w-full
                  px-4
                  py-2.5
                  text-sm
                  font-bold
                  text-white
                  transition-all
                  duration-200
                  bg-gray-900
                "
                @click="show = true"
              >
                More Info
              </button>
            </span>
          </div>
        </div>
      </div>
    </div>
    <!--End of Vif-->
  </section>
</template>

<script setup>
const supabase = useSupabaseClient();

const { data, error } = await supabase.from('productinfo_testv11').select();
const props = defineProps({
  show: {
    type: Boolean,
    default: false,
    required: true,
  }
});

console.log(props.show);
</script>

<style lang="scss">
////
/// Star Rating
/// @group components
/// @author Damián Muti
////

@import url('https://fonts.googleapis.com/css?family=Roboto+Slab:400');

///
$rating-min-value: 0 !default;
///
$rating-max-value: 5 !default;
///
$rating-steps-value: 0.25 !default;
///
$rating-color-empty: '%23ddd' !default;
///
$rating-color-full: gold !default;
///
$rating-color-hover: grey !default;
/// This variable is a map containing the "d" attribute of each of the SVG icons
$rating-icons-paths: (
  quarter: 'M196.208 415.2v-224.8l-139.504 20.272 100.944 98.384-23.84 138.928z',
  half:
    'M258.672 64l-62.384 126.4-139.504 20.272 100.944 98.384-23.84 138.928 124.768-65.6v-318.4z',
  three-quarters:
    'M321.616 190.496l-0.656-0.096-62.384-126.4-62.384 126.4-139.504 20.272 100.944 98.384-23.84 138.928 124.768-65.6 63.024 33.136z',
  full:
    'M457.888 210.672l-139.504-20.272-62.384-126.4-62.384 126.4-139.504 20.272 100.944 98.384-23.84 138.928 124.768-65.6 124.768 65.6-23.84-138.928c0 0 100.944-98.384 100.944-98.384z',
);

/// Creates a dynamic list of values that increment each .25 from 0 to 5
/// @return {list}
@function rating-values() {
  $rating-values: ();

  @for $i
    from $rating-min-value
    through (calc($rating-max-value / $rating-steps-value))
  {
    $rating-value: abs($i * $rating-steps-value);
    $rating-values: append($rating-values, $rating-value, 'comma');
  }

  @return $rating-values;
}

/// Generates an SVG with a given fill color depending on the type of icon passed as parameter. The SVG string is scaped for cross-browser support.
/// @param {string} $icon - Type of icon. Accepted values: `quarter`, `half`, `three-quarters` or `full`.
/// @param {color} $color - Passes the fill color of the SVG icon that is being generated. Note: Hexa color values must be escaped for cross-browser support.
/// @return {string} background value.
@function get-icon($icon, $color) {
  @if not index(quarter half three-quarters full, $icon) {
    @error "Interaction type must be either `quarter`, `half`, `three-quarters` or `full`.";
  }

  @return url('data:image/svg+xml;utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22512%22%20height%3D%22512%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20fill%3D%22' + $color + '%22%20d%3D%22' + map-get(
        $rating-icons-paths,
        $icon
      ) + '%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E')
    center / cover no-repeat;
}

/// This is a CSS-only star rating component that shows the proper rating depending on a data-attribute value. JS logic behind this component should round up values per quarter.
/// @param {number} $star-size [20px] - Provides width and height for each of the stars.
/// @param {string} $rating-element [button] - Element to use for each of the stars.
/// @param {string} $interaction-type [representative] - Indicates whether this component should be clickable or representative. Accepted values: `clickable` or `representative`.
/// @example scss
///   .class {
///     c-rating(toem(20px), button, clickable);
///   }
/// @example markup
///   <div class="c-rating" data-rating-value="3.25">
///     <span>1</span>
///     <span>2</span>
///     <span>3</span>
///     <span>4</span>
///     <span>5</span>
///   </div>
@mixin c-rating(
  $star-size: 20px,
  $star-element: button,
  $interaction-type: representative
) {
  @if not index(clickable representative, $interaction-type) {
    @error "Interaction type must be either `clickable` or `representative`.";
  }

  #{$star-element} {
    display: inline-block;
    float: left;
    width: $star-size;
    height: $star-size;
    border: 0;
    text-indent: -9999px;
    outline: none;
    background: get-icon(full, $rating-color-empty);

    @if $interaction-type == clickable {
      cursor: pointer;
      transition: background 0.25s ease;

      // Override background images on hover state
      &:hover,
      &:hover ~ #{$star-element} {
        background: get-icon(full, $rating-color-empty) !important;
      }
    }
  }

  // Override background images on hover state
  @if $interaction-type == clickable {
    &:hover {
      #{$star-element} {
        background: get-icon(full, $rating-color-hover) !important;
      }
    }
  }

  @each $rating-value in rating-values() {
    // Get the next higher integer.
    $rating-value-ceil: ceil($rating-value);

    &[data-rating-value='#{$rating-value}'] {
      #{$star-element}:nth-child(-n + #{$rating-value-ceil}) {
        background: get-icon(full, $rating-color-full);
      }

      #{$star-element}:nth-child(#{$rating-value-ceil}) {
        // Evaluate which fraction of a star this value is and add the proper background
        @if str-slice('#{$rating-value}', 2, 4) == '.25' {
          background: get-icon(quarter, $rating-color-full),
            get-icon(full, $rating-color-empty);
        } @else if str-slice('#{$rating-value}', 2, 4) == '.5' {
          background: get-icon(half, $rating-color-full),
            get-icon(full, $rating-color-empty);
        } @else if str-slice('#{$rating-value}', 2, 4) == '.75' {
          background: get-icon(three-quarters, $rating-color-full),
            get-icon(full, $rating-color-empty);
        }
      }
    }
  }
}

/*
 * General styles.
 * Not necessary for the component to work
*/

/// Convert to EMs function
/// @param {number} target - The value to be converted
/// @param {number} context [$msuxf-font-size] The base font size
/// @return {em} value
@function toem($target, $context: 16px) {
  @if $target == 0 {
    @return 0;
  }

  @return calc($target / $context) + 0em;
}

.c-rating {
  @include c-rating(toem(20px), button, clickable);

  &--small {
    font-size: 70%;
  }

  &--big {
    font-size: 150%;
  }
}
</style>

LoadItem.vue

<template>
  <TransitionRoot as="template" :show="show">
    <Dialog as="div" class="relative z-10" @close="open = false">
      <div class="fixed inset-0" />

      <div class="fixed inset-0 overflow-hidden">
        <div class="absolute inset-0 overflow-hidden">
          <div
            class="
              pointer-events-none
              fixed
              inset-y-0
              right-0
              flex
              max-w-full
              pl-10
            "
          >
            <TransitionChild
              as="template"
              enter="transform transition ease-in-out duration-500 sm:duration-700"
              enter-from="translate-x-full"
              enter-to="translate-x-0"
              leave="transform transition ease-in-out duration-500 sm:duration-700"
              leave-from="translate-x-0"
              leave-to="translate-x-full"
            >
              <DialogPanel class="pointer-events-auto w-screen max-w-md">
                <div
                  class="
                    flex
                    h-full
                    flex-col
                    overflow-y-scroll
                    bg-white
                    shadow-xl
                  "
                >
                  <div class="bg-indigo-700 py-6 px-4 sm:px-6">
                    <div class="flex items-center justify-between">
                      <DialogTitle
                        class="text-base font-semibold leading-6 text-white"
                        >Panel title</DialogTitle
                      >
                      <div class="ml-3 flex h-7 items-center">
                        <button
                          type="button"
                          class="
                            rounded-md
                            bg-indigo-700
                            text-indigo-200
                            hover:text-white
                            focus:outline-none focus:ring-2 focus:ring-white
                          "
                          @click="(open = false), (show = false)"
                        >
                          <span class="sr-only">Close panel</span>
                          <XMarkIcon class="h-6 w-6" aria-hidden="true" />
                        </button>
                      </div>
                    </div>
                    <div class="mt-1">
                      <p class="text-sm text-indigo-300">
                        Lorem, ipsum dolor sit amet consectetur adipisicing elit
                        aliquam ad hic recusandae soluta.
                      </p>
                    </div>
                  </div>
                  <div class="relative flex-1 py-6 px-4 sm:px-6">
                    <!-- Your content -->
                  </div>
                </div>
              </DialogPanel>
            </TransitionChild>
          </div>
        </div>
      </div>
    </Dialog>
  </TransitionRoot>
</template>

<script setup>
import { ref } from 'vue';
import {
  Dialog,
  DialogPanel,
  DialogTitle,
  TransitionChild,
  TransitionRoot,
} from '@headlessui/vue';
import { XMarkIcon } from '@heroicons/vue/24/outline';

const open = ref(true);
const props = defineProps(['show']);
</script>

我希望在关闭名为Loaditem的组件后,可以再次在ProductGrid中重新激活它,因为目前它只被触发一次。
我是Vue/Nuxt的新手,所以请善待我!
谢谢大家!

fdx2calv

fdx2calv1#

要修复和解决问题,请在LoadItem. vue中使用emit事件。类似于:
LoadItem.vue - Options API上的更改

<script>
export default {
  props: {
    show: {
      type: Boolean,
      default: false,
      required: true,
    },
  },
  methods: {
    emitClose() {
      this.$emit("close");
    },
  },
};
</script>

and on template:
<Dialog as="div" class="relative z-10" @close="emitClose">

组成API

<script setup>
import { ref, defineProps, defineEmit } from 'vue';

const props = defineProps({
  show: {
    type: Boolean,
    default: false,
    required: true,
  },
});

const emitClose = () => {
  defineEmit(['close']);
  emit('close');
};
</script>

在ProductGrid.vue组件上:

<!-- ProductGrid.vue -->
<LoadItem v-if="show" :show="show" @close="show = false" />

相关问题