【问题标题】:Dynamic pricing calculator in vue jsvue js中的动态定价计算器
【发布时间】:2021-06-24 00:48:09
【问题描述】:

*已编辑

我正在使用 vue js 构建一个动态定价计算器功能。我已经编写了代码,但仍然存在一些问题使我制作的功能无法正常工作。我有一个下拉菜单,单击它会显示不同的选项卡和不同的内容(动态组件)。而且我还有一张详细信息和价格的估价卡,每个项目都可以删除。

我有几个问题如下:

  1. 当我在Storage选项卡上,选择几个选项后提交数据时,软件选项卡的详细信息和价格也出现在估算卡中。我想要的只是Storage 的定价细节。同样,如果我只是在Software 选项卡中提交,那么Software 选项卡中只会显示详细信息和价格。而如果我在Software和Storage提交,就会出现两者的结果。

  2. 当我在Storage 选项卡上提交数据并转到Software 选项卡时,估算卡上的价格详细信息消失了。我希望数据仍然出现。如果我使用 <keep-alive> 是不可能的,因为它不是动态组件。

  3. 我在估算卡中有删除按钮项目。我想要的将根据单击的选项删除该项目。但仍然不能很好地工作。

目前,我只有 2 个选项卡,存储和软件。如果我有其他选项卡,如何使这个系统动态化?

谁能帮我解决这个问题并一步一步解释?

这是我在 Codesandbox 上制作的代码:https://codesandbox.io/s/dynamic-price-calculator-o77ig

【问题讨论】:

    标签: javascript vue.js vuejs3


    【解决方案1】:

    这是完成这项工作的一组非常粗糙的组件 - 没有 SUBMIT 按钮。

    Vue.component("ProductSetup", {
      props: ['productKey', 'product'],
      methods: {
        handleInputChange(e) {
          this.$emit("update:product-type", {
            ...e,
            product: this.productKey,
          })
        },
        handleQuantityChange(e) {
          this.$emit("update:product-quantity", {
            ...e,
            product: this.productKey,
          })
        },
      },
      template: `
        <div>
          <label
            v-for="(val, key) in product.types"
            :key="key"
          >
            {{ key }}
            <input
              type="radio"
              :value="val"
              :name="productKey"
              @change="() => handleInputChange({ type: key })"
            />
          </label>
          <input
            type="number"
            min="0"
            @input="(e) => handleQuantityChange({ quantity: e.target.value })"
          />
        </div>
      `,
    })
    
    Vue.component("PriceEstimate", {
      props: ["products"],
      template: `
        <div>
          <div
            v-for="(product, productKey) in products"
          >
            {{ productKey }}<br />
            {{ productKey }} {{ product.chosen }}: {{ product.types[product.chosen] }}<br />
            Quantity {{ productKey }}: {{ product.quantity * product.pricePerPiece }}<br />
            TOTAL: {{ product.types[product.chosen] + product.quantity * product.pricePerPiece }}
          </div>
        </div>
      `,
    })
    
    new Vue({
      el: "#app",
      computed: {
        estimates() {
          return Object.fromEntries(
            Object.entries(
              this.products
            ).filter(([key, val]) => {
              return val.chosen && val.quantity
            })
          )
        },
      },
      data() {
        return {
          products: {
            storage: {
              chosen: null,
              types: {
                type1: 60,
                type2: 70,
              },
              pricePerPiece: 20,
              quantity: null,
            },
            os: {
              chosen: null,
              types: {
                os1: 60,
                os2: 70,
                os3: 80,
              },
              pricePerPiece: 35,
              quantity: null,
            },
          },
        }
      },
      methods: {
        handleUpdateProduct({
          type,
          product
        }) {
          this.products[product]["chosen"] = type
        },
        handleUpdateQuantity({
          quantity,
          product
        }) {
          this.products[product]["quantity"] = quantity
        }
      },
      template: `
        <div>
          <div
            v-for="(obj, product) in products"
          >
            Chosen {{ product }}: {{ obj.chosen }}<br />
            Quantity of {{ product }}: {{ obj.quantity }}
            <hr />
            <product-setup
              :product-key="product"
              :product="obj"
              @update:product-type="(e) => handleUpdateProduct(e)"
              @update:product-quantity="(e) => handleUpdateQuantity(e)"
            />
            <hr />
          </div>
          <price-estimate
            :products="estimates"
          />
        </div>
      `,
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app"></div>

    【讨论】:

      【解决方案2】:

      问题出在 priceEstimationData 接收到的参数中,它确实有 servicesDuration 和 servicesTypePrice。

      在 ServiceCalculator.vue 中,“数据”是:

      var data = {
          servicesTypeName: selectedServicesType.name,
          servicesTypeValue: selectedServicesType.value,
          qunantity: this.quantiti,
          durationServices: this.durationServices,
      };
      

      您还必须传递属性 servicesDuration 和 servicesTypePrice。

      问候

      【讨论】:

      • 我添加 servicesTypePrice: this.servicesTypePrice, serviceDuration: this.servicesDuration 仍然无法正常工作
      • 我看到的是设置属性 priceEstimationData 时没有一致性。调用“setPriceEstimationData”时,您必须传递所有属性。作为快速修复,您可以在“PriceEstimation.vue”中执行此操作: watch: { priceEstimationData: function (data) { ... this.servicesType = data.servicesTypeName; this.servicesTypePrice = data.servicesTypeValue ?数据服务类型值:0; this.servicesQuantity = 数据.数量; this.servicesDuration = data.durationServices ? data.durationServices:0; ... },问候
      【解决方案3】:
      1. 您必须使 priceEstimationData 动态化。您可以在不使用手表的情况下显示来自道具的数据。我在这里只提供一些代码。如需完整版,请前往代码框。
      <!-- PriceEstimation.vue -->
      
      <template v-if="priceEstimationData">
          <div
            :key="id"
            v-for="(data, id) in priceEstimationData"
            class="estimation-category"
          >
            <div class="category-price d-flex justify-content-between">
            {{ data ? data.type[0].toUpperCase() + data.type.slice(1) : ""}}
              <a href="#" @click="removeItem(id)">Delete</a>
            </div>
            <table class="table table-borderless">
              <tbody>
                <tr>
                  <td>
                    <p>
                      Storage Type: <span>{{ data.typeName }}</span>
                    </p>
                    <p>
                      Quantity Storage: <span>{{ data.qunantity }}</span>
                    </p>
                    <p>
                      Duration Storage: <span>{{ data.duration }}</span>
                    </p>
                  </td>
                  <td class="text-right">
                    <p>${{ data.typeValue }}</p>
                    <p>${{ data.qunantity * data.quantityPrice }}</p>
                    <p>${{ data.duration * data.durationPrice }}</p>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </template>
      
      1. 查看您的代码后。我注意到您正在使用 watch 属性。我已经删除了 watch 属性以使估计数据仍然存在。请参阅下面的代码
      // TheCalculator.vue
      
      // remove watch that makes the priceEstimationData null
      /* watch: {
       selectedTab: function () {
         this.priceEstimationData = null;
       },
      }, */
      computed: {
       selectedTabProps() {
         return this.selectedTab === "storage-calculator"
           ? { event: this.setPriceEstimationData }
           : null;
       },
      },
      
      1. 我已修改您的代码并将 removeItem 方法移至父级。因为孩子只读取数据。见下文
      // TheCalculator.vue
      
      methods: {
       setSelectedTab(tab) {
        this.selectedTab = tab;
       },
       setPriceEstimationData(data) {
        this.priceEstimationData.push(data);
       },
       removeItem(id) {
        // remove findIndex function
        this.priceEstimationData.splice(id, 1);
       },
      },
      

      我修改了TheCalculator.vue、PriceEstimation.vue、ServiceCalculator.vue和StorageCalculator.vue。

      编辑

      我已修复 ServiceCalculator.vue 中的持续时间错误

      // ServiceCalculator.vue
      
      // fixes duration bug
      updateDurationServices(val) {
       this.duration = val;
      },
      

      代码沙盒:https://codesandbox.io/s/dynamic-price-calculator-forked-ls7n6

      享受吧!

      【讨论】:

        猜你喜欢
        • 2021-09-25
        • 1970-01-01
        • 1970-01-01
        • 2020-04-03
        • 2020-11-17
        • 2021-07-01
        • 2018-02-18
        • 1970-01-01
        • 2021-12-29
        相关资源
        最近更新 更多