Vue组件中的递归组件错误

时间:2018-03-23 09:30:34

标签: javascript recursion vue.js

我一直在搜索SO和Vue论坛上的任何与递归组件相关的问题,当我最终尝试了一些错误时,它会导致另一个错误,所以这里是分解:

我有一个 Contents.vue 组件,里面有 Item.vue

<template>
  <div class="content__wrapper wrapper" :class="{'expanded-content': state.expansion}">
    <p v-if="liked && items.length === 0" class="title">{{ data.defaults.add_liked }}</p>
    <p v-if="!liked && assemble_contents_array.length === 0" class="title">{{ data.defaults.products_missing }}</p>
    <Item v-for="(item, index) in liked ? items : assemble_contents_array" :key="`item-${index}`" :full_data="items" :item_data="item" :ind="index" 
      :expand="state.item_for_expansion === index" :is_expansion="state.expansion" :defaults="data.defaults"
      :is_similar_item="false"/>
  </div>
</template>

<script>
import Item from './Item'

export default {
  props: ["data", "items", "content_categories", "liked"],
  data(){
    return{
      state:{
        item_for_expansion: null,
        expansion: false
      }
    }
  },
  computed:{
    assemble_contents_array(){
      if(!this.liked){
        let contenst_array = []
        this.content_categories.sub_categories
          .map(type => this.data[this.content_categories.category][type])
          .forEach(e => e.forEach(c => contenst_array.push(c)))

        return contenst_array
      }
    }
  },
  created(){
    this.$eventHub.on("expand_item", index => {
      if(index === "")
        this.state.expansion = false
      else  
        this.state.expansion = true
      this.state.item_for_expansion = index
    })
  },
  components:{
    Item
  }
}
</script>

以下是 Item.vue ,其中包含 Similar-items.vue

<template>
 <div class="item__wrapper" :class="{'expanded': expand, 'shrink' : !expand && is_expansion}">
    <div v-if="expand"> 
      <span class="item__close" @click="expansion">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
          <path d="M23 20.168l-8.185-8.187 8.185-8.174-2.832-2.807-8.182 8.179-8.176-8.179-2.81 2.81 8.186 8.196-8.186 8.184 2.81 2.81 8.203-8.192 8.18 8.192z"/>
        </svg>
      </span>
      <Gallery :main="item_data.img" :images="item_data.images"/>
      <Checkout v-if="defaults.shop" :data="item_data" :defaults="defaults" class="right-panel"/>
      <Summary v-else :data="item_data" :defaults="defaults" class="right-panel"/>
      <div class="item__description">
        <p v-if="item_data.type">
          {{ defaults.further_reading }}
        </p>
        <div v-html="item_data.desc">
          {{ item_data.desc }}
        </div>
      </div>
      <SimilarItems :data="full_data"/>
    </div>
    <div v-else>
      <svg v-if="!state.liked" @click="add_to_liked" class="item__like" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.653 19.415c-1.162 1.141-2.389 2.331-3.653 3.585-6.43-6.381-12-11.147-12-15.808 0-4.005 3.098-6.192 6.281-6.192 2.197 0 4.434 1.042 5.719 3.248 1.279-2.195 3.521-3.238 5.726-3.238 3.177 0 6.274 2.171 6.274 6.182 0 1.269-.424 2.546-1.154 3.861l-1.483-1.484c.403-.836.637-1.631.637-2.377 0-2.873-2.216-4.182-4.274-4.182-3.257 0-4.976 3.475-5.726 5.021-.747-1.54-2.484-5.03-5.72-5.031-2.315-.001-4.28 1.516-4.28 4.192 0 3.442 4.742 7.85 10 13l2.239-2.191 1.414 1.414zm7.347-5.415h-3v-3h-2v3h-3v2h3v3h2v-3h3v-2z"/></svg>
      <svg v-else @click="add_to_liked" class="item__like" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.582 19.485c-1.141 1.119-2.345 2.287-3.582 3.515-6.43-6.381-12-11.147-12-15.808 0-4.005 3.098-6.192 6.281-6.192 2.197 0 4.434 1.042 5.719 3.248 1.279-2.195 3.521-3.238 5.726-3.238 3.177 0 6.274 2.171 6.274 6.182 0 1.577-.649 3.168-1.742 4.828l-1.447-1.447c.75-1.211 1.189-2.341 1.189-3.381 0-2.873-2.216-4.182-4.274-4.182-3.257 0-4.976 3.475-5.726 5.021-.747-1.54-2.484-5.03-5.72-5.031-2.315-.001-4.28 1.516-4.28 4.192 0 3.442 4.742 7.85 10 13l2.168-2.121 1.414 1.414zm7.418-5.485h-8v2h8v-2z"/></svg>
      <div @click="expansion">
        <img :src="item_data.img" class="item__image">
        <p class="item__title">{{ item_data.name }}</p>
        <p class="item__price" v-if="item_data.type">${{ item_data.price }}</p>
      </div>
    </div>
  </div>
</template>

<script>
import Gallery from './utils/gallery'
import Checkout from './utils/checkout'
import Summary from './utils/summary'
import SimilarItems from './utils/similar-items'

export default {
  name: "Item",
  props: [ "full_data", "item_data", "ind", "expand", "is_expansion", "defaults", "is_similar_item"],
  data(){
    return{
      state:{
        get_parent_height: 0,
        scrolled_depth: 0,
        liked: this.item_data.liked === undefined ? false : this.item_data.liked
      }
    }
  },
  methods:{
    /*
    *  Adds item to liked
    */
    add_to_liked(){
      this.state.liked = !this.state.liked
      this.$eventHub.emit("adjust_liked", this.state.liked)
      this.$eventHub.emit("add_or_delete_item", this.item_data, this.state.liked, "liked_items")
    },
    /*
    *  Expands the item to show detail page
    */
    expansion(){
      if(this.expand){
        this.$eventHub.emit("clear_size")
      }
      else{
        this.state.scrolled_depth = document.querySelector("html").scrollTop
      }

      this.$eventHub.emit(this.is_similar_item ? "expand_similar_item" : "expand_item", this.expand ? "" : this.ind)

      // Scroll to previously scrolled
      setTimeout( _ => document.querySelector("html").scrollTop = !this.expand ? this.state.scrolled_depth : 0, 100) 
    }
  },
  beforeUpdate(){
    this.state.liked = this.item_data.liked === undefined ? false : this.item_data.liked
  },
  components:{
    Gallery,
    Checkout,
    Summary,
    SimilarItems
  }
}
</script>

现在最后,这里有 Similar-items.vue ,其中再次包含 Item.vue

<template>
  <div class="similar-items">
    <Item v-for="(item, ind) in data" :key="'similar-item-'+ind" class="similar-items__item" :data="item" :ind="ind" 
      :expand="state.item_for_expansion === ind" :is_expansion="state.expansion" :defaults="data.defaults"
      :is_similar_item="true" :is_firts="false"/>
  </div>
</template>

<script>
import Item from '../Item'

export default {
  props: ["data"],
  name: "similar-items",
  data(){
    return{
      state:{
        item_for_expansion: null,
        expansion: false
      }
    }
  },
  methods: {

  },
  created(){
    this.$eventHub.on("expand_similar_item", index => {
      if(index === "")
        this.state.expansion = false
      else  
        this.state.expansion = true
      this.state.item_for_expansion = index
    })
  },
  components:{
    Item
  }
}
</script>

哪位给了我: Unknown custom element: <Item> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

所以我尝试添加:

beforeCreate() {
  this.$options.components.Item = require('./Item').default
}

Contents.vue ,我删除了import Itemcomponents: { Item },但我在 Similar-items.vue <中保留了相同的内容/ p>

这给了我这个错误:Unknown custom element: <Item> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

然后我尝试添加:

beforeCreate() {
  this.$options.components.Item = require('../Item')
},

Similar-items.vue 并删除import Itemcomponents: { Item }

这给了我:Failed to mount component: template or render function not defined.

简而言之, Contents.vue 里面有 Item.vue ,里面有 Similar-items.vue ,在其中有 Item.vue ,以及递归发生的地方。

现在我有点迷失了。

就像一个FYI:我已经尝试了一个有条件的 Similar-items.vue 来强调 Item.vue ,但仍然没有用。

1 个答案:

答案 0 :(得分:0)

首先,您应该在Item.vue中的SimilarItems组件上设置条件渲染,以防止渲染循环。如果当前已迭代的项目已经是类似项目,我们不希望显示更多项目。

<SimilarItems v-if="!is_similar_item" :data="full_data"/>

导入Vue组件时,请务必详细说明扩展文件。如果在您的文件夹中,您有一个像这样的独立组件:

  • Item.vue
  • Item.scss
  • Item.js

导入将首先选择.js,这可能只包含您的脚本而没有模板键。