【问题标题】:Change content on page on clicking a vue js child element单击 vue js 子元素更改页面上的内容
【发布时间】:2019-10-30 17:02:57
【问题描述】:

我正在创建一个将在页面上显示产品的应用。这些产品中的每一个都有一个功能列表,例如“电池电量”、“充电时间”,甚至只是一个描述,每个功能都会有所不同。我的问题是,我怎样才能制作一个可点击的元素,点击后会找到与该按钮/图标关联的数据,然后更新页面上的内容以反映这一点?此内容可能在也可能不在某种 v-for 循环中。

请参阅下面的示例,说明我拥有什么以及我想要实现什么。

子组件:

<template>
  <li>
    <button @click="$emit('changeProductData', feature)">
      <img :src="require('../assets/images/' + feature.item.img)" />
    </button>
  </li>
</template>

<script>
export default {
  props: {
    feature: Object
  }
}
</script>

父组件:

<template>
  <div>
    <div v-for="product in getProduct(productId)" :key="product.productId">
      {{ product }}
      <Halo
        :featuresCount="
          `circle-container-` + product.features.length.toString()
        "
      >
        <Feature
          v-for="(feature, key, index) in product.features"
          :key="index"
          :feature="feature"
          @changeProductData="something" // this is where we call the custom event
        ></Feature>
      </Halo>

      <h1>This is where I want to dynamically inject the title for each feature on clicking corresponding feature</h1>

    </div>
  </div>
</template>

<script>
import Halo from '@/components/ProductHalo.vue'
import Feature from '@/components/ProductFeature.vue'
import json from '@/json/data.json'

export default {
  name: 'ProductSingle',
  components: {
    Halo,
    Feature
  },
  data() {
    return {
      products: json
    }
  },
  computed: {
    productId() {
      return this.$route.params.id
    }
  },
  methods: {
    getProduct(id) {
      let data = this.products
      return data.filter(item => item.productId == id)
    },
    something(e) {
      // ideally we have a method here that grabs the corresponding 
      //feature then displays it on the page
      console.log(e.item.text)
    }
  }
}
</script>

我的 console.log 调用确实从我的 data.json 调用了正确的标题,如下所示:

[
  {
    "productId": 1,
    "name": "Test 1",
    "image": "sample.jpg",
    "features": [
      {
        "item": {
          "text": "Something else",
          "img": "sample.jpg"
        }
      },
      {
        "item": {
          "text": "Turbo",
          "img": "wine.jpg"
        }
      },
      {
        "item": {
          "text": "Strong",
          "img": "sample.jpg"
        }
      }
    ]
  }
]

所以我似乎可以根据每个项目的点击来访问我的标题,只是不确定如何在任意位置显示它!有没有神奇的 vue js'ers 可以解决这个谜题? TIA

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    选项1:更改子组件

    我不会仅为一个功能按钮创建组件,而是将整个功能列表嵌入到带有h1 的组件中,您希望在其中显示所选功能。因此,子组件将如下所示:

    <template>
      <div>
        <li v-for="(feature, key, index) in features" :key="index">
          <button @click="setFeature(feature)">
            <img :src="require('../assets/images/' + feature.item.img)" />
          </button>
        </li>
        <h1>{{ clickedFeuatureText }}</h1>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
            clickedFeuatureText:null
        }
      },
      methods: {
        setFeature(e){
          this.clickedFeuatureText = e.item.text
        }
      },
      props: {
        features: Array
      }
    }
    </script>
    

    这里是父组件有相应的变化:

    <template>
      <div>
        <div v-for="product in getProduct(productId)" :key="product.productId">
          {{ product }}
          <Halo
            :featuresCount="
              `circle-container-` + product.features.length.toString()
            "
          >
            <Feature :features=" product.features"></Feature>
          </Halo>
        </div>
      </div>
    </template>
    
    <script>
    import Halo from '@/components/ProductHalo.vue'
    import Feature from '@/components/ProductFeature.vue'
    import json from '@/json/data.json'
    
    export default {
      name: 'ProductSingle',
      components: {
        Halo,
        Feature
      },
      data() {
        return {
          products: json
        }
      },
      computed: {
        productId() {
          return this.$route.params.id
        }
      },
      methods: {
        getProduct(id) {
          let data = this.products
          return data.filter(item => item.productId == id)
        }
      }
    }
    </script>
    

    选项 2:为一个产品创建新组件

    另一种方法是保持子组件不变,但创建代表列表中一个产品的新组件:

    <template>
      <div>
          {{ product }}
          <Halo
            :featuresCount="
              `circle-container-` + product.features.length.toString()
            "
          >
            <Feature
              v-for="(feature, key, index) in product.features"
              :key="index"
              :feature="feature"
              @changeProductData="setFeatureText"
            ></Feature>
          </Halo>
    
          <h1>{{ clickedFeature}}</h1>
    
        </div>
      </div>
    </template>
    
    <script>
    import Feature from '@/components/ProductFeature.vue'
    import Halo from '@/components/ProductHalo.vue'
    
    export default {
      name: 'product',
      components: {
        Feature,
        Halo 
      },
      data () {
        return {
          clickedFeature: null
        }
      },
      props: {
        product: Object
      },
      methods: {
        setFeatureText(e) {
          this.clickedFeature = e.item.text
        }
      }
    }
    </script>
    

    然后使用新的Product 组件:

    <template>
      <div>
        <product 
          v-for="product in getProduct(productId)" 
          :key="product.productId" 
          :product="product"
        ></product>
      </div>
    </template>
    
    <script>
    import Product from '@/components/Product.vue'
    import json from '@/json/data.json'
    
    export default {
      name: 'ProductSingle',
      components: {
        Product
      },
      data() {
        return {
          products: json
        }
      },
      computed: {
        productId() {
          return this.$route.params.id
        }
      },
      methods: {
        getProduct(id) {
          let data = this.products
          return data.filter(item => item.productId == id)
        }
      }
    }
    </script>
    

    【讨论】:

    • 感谢您的回答 Lana,我最终找到了适用于案例的解决方案。但这看起来是个不错的解决方案!
    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 2015-11-01
    • 2017-05-08
    • 2016-11-08
    相关资源
    最近更新 更多